1

我正在用 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) 

这似乎有点丑陋。是否有某种惯用的方法来做到这一点?那么错误检查呢?我的函数无法优雅地处理错误,例如以愚蠢的顺序传递参数。

此外,重要的是,调度中的每个函数都接受不同数量的参数,所以无论如何我都不能静态地执行此操作(如上所述)。这太糟糕了unCurry command args不是有效的 Haskell。

4

1 回答 1

7

一种方法是将您的函数包装在执行进一步命令行处理的函数中。例如

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

您可以通过让包装函数的变体执行错误检查,根据需要将它们的(部分)参数转换为Ints / 自定义数据类型 / 等来扩展它。

正如 dbaupp 所指出的,我们在getArgs上面进行模式匹配的方式并不安全。更好的方法是

run :: [String] -> IO ()
run [] = showUsageMessage
run (command : args)
   = case lookup command dispatch of
          Just act -> act args
          Nothing  -> showUsageMessage

main = run =<< getArgs
于 2012-04-04T08:13:13.523 回答