我正在Haskell中编写一个小命令行程序。我需要它根据命令行参数调度到正确的加密函数。我已经走了那么远,但后来我需要剩下的参数作为参数传递给函数。我读过:
http://learnyouahaskell.com/input-and-output
这让我走到了这一步:
import qualified CaesarCiphers
import qualified ExptCiphers
dispatch::[(String, String->IO ())]
dispatch = [("EEncipher", ExptCiphers.exptEncipherString)
("EDecipher", ExptCiphers.exptDecipherString)
("CEncipher", CaesarCiphers.caesarEncipherString)
("CDecipher", CaesarCiphers.caesarDecipherString)
("CBruteForce", CaesarCiphers.bruteForceCaesar)]
main = do
(command:args) <- getArgs
每个函数都需要一些我不知道的参数,直到运行时。如何将它们传递给函数,因为它们将被绑定在列表中?我只是手动抓住它们吗?像:
exampleFunction (args !! 1) (args !! 2)
这看起来有点难看。是否有某种惯用的方法来做到这一点?那么错误检查呢?我的功能无法正常处理错误,例如以愚蠢的顺序获取传递的参数。
另外,重要的是,dispatch中的每个函数都使用不同数量的参数,所以我无论如何都不能静态地执行此操作(如上所述。)它太糟糕unCurry command args
无效Haskell。
答案 0 :(得分:7)
一种方法是将函数包装在进一步执行命令行处理的函数中。 e.g。
dispatch::[(String, [String]->IO ())]
dispatch = [("EEncipher", takesSingleArg ExptCiphers.exptEncipherString)
("EDecipher", takesSingleArg ExptCiphers.exptDecipherString)
("CEncipher", takesTwoArgs CaesarCiphers.caesarEncipherString)
("CDecipher", takesTwoArgs CaesarCiphers.caesarDecipherString)
("CBruteForce", takesSingleArg CaesarCiphers.bruteForceCaesar)]
-- a couple of wrapper functions:
takesSingleArg :: (String -> IO ()) -> [String] -> IO ()
takesSingleArg act [arg] = act arg
takesSingleArg _ _ = showUsageMessage
takesTwoArgs :: (String -> String -> IO ()) -> [String] -> IO ()
takesTwoArgs act [arg1, arg2] = act arg1 arg2
takesTwoArgs _ _ = showUsageMessage
-- put it all together
main = do
(command:args) <- getArgs
case lookup command dispatch of
Just act -> act args
Nothing -> showUsageMessage
您可以通过让包装函数的变体执行错误检查来扩展它,并根据需要将其参数转换为Int
s / custom数据类型/ etc。
正如dbaupp所说,我们在getArgs
上进行模式匹配的方式并不安全。更好的方法是
run :: [String] -> IO ()
run [] = showUsageMessage
run (command : args)
= case lookup command dispatch of
Just act -> act args
Nothing -> showUsageMessage
main = run =<< getArgs