使用Haskell中的命令行参数调度以更正函数

时间:2012-04-04 05:37:50

标签: haskell io monads

我正在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。

1 个答案:

答案 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