2012-04-04 72 views
1

我在Haskell中编写了一个命令行程序。我需要它根据命令行参数分派到正确的加密函数。我已经得到了那么多,但是我需要剩下的参数作为参数传递给函数。我读过:使用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 

每个功能需要一些论据,我不知道,直到运行时。如何将这些函数传递给一个函数,看看它们将被绑定在一个列表中?我只是手动抓住他们?像:

​​

这似乎有点丑。是否有某种惯用的方式来做到这一点?那错误检查呢?我的功能没有装备来优雅地处理错误,例如在白痴命令中传递参数。

此外,重要的是,派遣中的每个函数都需要不同数量的参数,所以我无法静态执行此操作(如上所示)。这太糟糕了unCurry command args不是有效的Haskell。

+1

[CmdLib](http://hackage.haskell.org/package/cmdlib)有一个有趣的解决方案来解决这个问题。不过,不要阻止你找到自己的解决方案! – ephemient 2012-04-04 06:42:07

回答

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 

您可以通过具有包装功能的变体进行错误检查他们的论据扩展此,转换(某些)到Int等必要的S /自定义数据类型/。

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

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

main = run =<< getArgs 
+2

应该避免'getArgs'上的模式匹配:如果没有参数,失败的匹配将产生一个不可捕获的异常。在分派之前最好捕获'getArgs'的整个输出并用'null'进行测试。 – huon 2012-04-04 15:31:55

+1

在包装函数中,参数的顺序似乎是错误的。签名是正确的,但在定义中您首先需要字符串列表。 – 2012-04-04 20:08:23

+0

谢谢@FrerichRaabe ---修复。 – dave4420 2012-04-04 20:34:30