Haskell 如何将选项记录转换为字符串列表?
我有一个需要转换为命令行参数的选项记录 例如:Haskell 如何将选项记录转换为字符串列表?,haskell,Haskell,我有一个需要转换为命令行参数的选项记录 例如: data Options=Options{optFoo::Maybe Int ,optYes::Bool ,optBar::可能是字符串 } 选项=选项{optFoo=3 ,opties=True ,optBar=Nothing } 调用:选项->IO() callThing opts=do callProcess“/usr/bin/thing”$optsToArgs opts --输出应为:[“--foo”,“3”,“-y”] optsToArg
data Options=Options{optFoo::Maybe Int
,optYes::Bool
,optBar::可能是字符串
}
选项=选项{optFoo=3
,opties=True
,optBar=Nothing
}
调用:选项->IO()
callThing opts=do
callProcess“/usr/bin/thing”$optsToArgs opts
--输出应为:[“--foo”,“3”,“-y”]
optsToArgs::选项->[字符串]
optsToArgs opts=???
我想象着可以使用列表单子,但我不知道如何使它工作
在我的具体案例中,Options包含大约20种不同的内容,因此使用嵌套if/case语句的解决方案并不理想
有没有解决这类问题的通用模式?不,据我所知,没有真正的内置方法来解决这类问题。您可以尝试使用某种泛型编程,但这可能不会很好地工作,而且相当困难。相反,我建议重组您的
选项
类型:
data Option
= Foo Int
| Yes
| Bar String
deriving (Eq, Show)
type Options = [Option]
optToArgs :: Option -> [String]
optToArgs opt = case opt of
Foo n -> ["--foo", show n]
Yes -> ["-y"]
Bar s -> ["--bar", s]
optsToArgs :: Options -> [String]
optsToArgs = concatMap optToArgs
那你会的
> optsToArgs [Foo 3, Yes]
["--foo", "3", "-y"]
> optsToArgs [Yes, Bar "test"]
["-y", "--bar", "test"]
这样,每个选项都有不同的构造函数。从单个选项到其相应参数的转换在一个位置处理,然后将多个选项转换为参数列表很简单。这还将允许您在需要时拥有更高层次的选项结构:
data FooOption
= Foo1 Int
| Foo2 Double
data BarOption
= Bar1 String
= Bar2 (String, String)
class Opt o where
toArgs :: o -> [String]
instance Opt FooOption where
toArgs (Foo1 n) = ["--foo", show n]
toArgs (Foo2 d) = ["--foo", show d]
instance Opt BarOption where
toArgs (Bar1 s) = ["--bar", s]
toArgs (Bar2 (s1, s2)) = ["--bar", s1, "--bar", s2]
data Option
= Foo FooOption
| Bar BarOption
| Yes
instance Opt Option where
toArgs (Foo f) = toArgs f
toArgs (Bar b) = toArgs b
toArgs Yes = ["-y"]
type Options = [Option]
instance Opt o => Opt [o] where
toArgs = concatMap toArgs
那你就只有
callThing = callProcess "/usr/bin/thing" . toArgs
例如:
> toArgs [Bar $ Bar2 ("hello", "world"), Foo $ Foo1 3, Yes]
["--bar", "hello", "--bar", "world", "--foo", "3", "-y"]
不,据我所知,没有一个真正的内在方法来做到这一点。您可以尝试使用某种泛型编程,但这可能不会很好地工作,而且相当困难。相反,我建议重组您的
选项
类型:
data Option
= Foo Int
| Yes
| Bar String
deriving (Eq, Show)
type Options = [Option]
optToArgs :: Option -> [String]
optToArgs opt = case opt of
Foo n -> ["--foo", show n]
Yes -> ["-y"]
Bar s -> ["--bar", s]
optsToArgs :: Options -> [String]
optsToArgs = concatMap optToArgs
那你会的
> optsToArgs [Foo 3, Yes]
["--foo", "3", "-y"]
> optsToArgs [Yes, Bar "test"]
["-y", "--bar", "test"]
这样,每个选项都有不同的构造函数。从单个选项到其相应参数的转换在一个位置处理,然后将多个选项转换为参数列表很简单。这还将允许您在需要时拥有更高层次的选项结构:
data FooOption
= Foo1 Int
| Foo2 Double
data BarOption
= Bar1 String
= Bar2 (String, String)
class Opt o where
toArgs :: o -> [String]
instance Opt FooOption where
toArgs (Foo1 n) = ["--foo", show n]
toArgs (Foo2 d) = ["--foo", show d]
instance Opt BarOption where
toArgs (Bar1 s) = ["--bar", s]
toArgs (Bar2 (s1, s2)) = ["--bar", s1, "--bar", s2]
data Option
= Foo FooOption
| Bar BarOption
| Yes
instance Opt Option where
toArgs (Foo f) = toArgs f
toArgs (Bar b) = toArgs b
toArgs Yes = ["-y"]
type Options = [Option]
instance Opt o => Opt [o] where
toArgs = concatMap toArgs
那你就只有
callThing = callProcess "/usr/bin/thing" . toArgs
例如:
> toArgs [Bar $ Bar2 ("hello", "world"), Foo $ Foo1 3, Yes]
["--bar", "hello", "--bar", "world", "--foo", "3", "-y"]
我将创建一个以选项名称作为参数的TypeClass
class ToCommand a where
toCmd :: a -> String -> [String]
instance ToCommand Int where
toCmd i n = [n,show i]
instance ToCommand Bool where
toCmd True n = [n]
toCmd False _ = []
instance (ToCommand a)=> ToCommand (Maybe a) where
toCmd Nothing _ = []
toCmd (Just a) n = toCmd a n
使用记录通配符,您可以
optToArgs opts{..} = concat (toCmd optFoo "--foo") (toCmd optYes "-y") ...
也许一个更通用的解决方案会起作用,但实施起来会更复杂。我会创建一个以选项名称为参数的TypeClass
class ToCommand a where
toCmd :: a -> String -> [String]
instance ToCommand Int where
toCmd i n = [n,show i]
instance ToCommand Bool where
toCmd True n = [n]
toCmd False _ = []
instance (ToCommand a)=> ToCommand (Maybe a) where
toCmd Nothing _ = []
toCmd (Just a) n = toCmd a n
使用记录通配符,您可以
optToArgs opts{..} = concat (toCmd optFoo "--foo") (toCmd optYes "-y") ...
也许可以使用更通用的解决方案,但实施起来会更复杂。如果“仅”将它们用作命令行参数,请使用已经存在的优秀库之一:。我已经成功地使用了optpass applicative和cmdargs。@JPMoresmau我的方案是另一个方向。我正在创建一个通过命令行进行抽象的库,因此命令行解析器在这种情况下没有帮助。哦,对不起,是的,我在您的代码中看到。如果“仅”将它们用作命令行参数,请使用已经存在的一个优秀库:。我已经成功地使用了optpass applicative和cmdargs。@JPMoresmau我的方案是另一个方向。我正在创建一个通过命令行进行抽象的库,因此命令行解析器在这种情况下没有帮助。哦,对不起,是的,我在你的代码中看到了我喜欢这个解决方案,但不幸的是,我只能选择一个答案。我选择了另一个,因为它更简单,并且直接适合我的场景,尽管我将尝试更改我的选项类型,看看我是否更喜欢它。我喜欢这个解决方案,但不幸的是,我只能选择一个答案。我选择了另一个,因为它更简单,并且直接适合我的场景,不过我将尝试更改我的选项类型,看看我是否更喜欢它。