不需要单子。您的标记想法是正确的,但是该信息的编码方式可能与您预期的不同。
我将从命令的定义开始:
type Command = [String] -> IO ()
然后你可以制作“命令制作者”功能:
mkCommand1 :: (String -> IO ()) -> Command
mkCommand2 :: (String -> String -> IO ()) -> Command
...
作为标签。如果你不喜欢函数的泛滥,你也可以做一个“命令 lambda”:
arg :: (String -> Command) -> Command
arg f (x:xs) = f x xs
arg f [] = fail "Wrong number of arguments"
这样您就可以编写如下命令:
printHelloName :: Command
printHelloName = arg $ \first -> arg $ \last -> do
putStrLn $ "Hello, Mr(s). " ++ last
putStrLn $ "May I call you " ++ first ++ "?"
当然mkCommand1
etc. 可以很容易地写成arg
, 为了两全其美。
至于包,Command
充分封装了多个子命令之间的选择,但它们不组合。这里的一种选择是更改Command
为:
type Command = [String] -> Maybe (IO ())
这允许您Command
通过采取不返回的第一个操作将多个 s 组合成一个Nothing
。现在你的包也只是类型的值Command
。(总的来说,对于 Haskell,我们对这些组合非常感兴趣——而不是包和列表,考虑如何将某个对象中的两个作为组合对象)
为了使您摆脱您肯定建立的愿望:(1)没有合理的方法来检测函数接受的参数数量*,并且(2)没有办法使类型依赖于数字,所以您将无法创建将参数数量mkCommand
作为第一个参数的 a Int
。
希望这有帮助。
- 在这种情况下,事实证明是有的,但我建议不要这样做,并认为这是一个坏习惯——当事情变得更抽象时,技术就会失效。但我是个纯粹主义者;更多的胶带Haskellers可能不同意我的观点。