Haskell:解析命令行参数

标签 haskell command-line-arguments

这更多的是一个风格问题,而不是一个如何做的问题。

所以我有一个需要两个命令行参数的程序:一个字符串和一个整数。

我是这样实现的:

main = do
  args@(~( aString : aInteger : [] ) ) <- getArgs
  let parsed@( ~[(n,_)] ) = reads aInteger
  if length args /= 2 || L.null parsed
    then do
      name <- getProgName
      hPutStrLn stderr $ "usage: " ++ name ++ " <string> <integer>"
      exitFailure
    else do
      doStuffWith aString n

虽然这有效,但这是我第一次在 Haskell 中真正使用命令行参数,所以我不确定这是否是一种非常尴尬且难以理解的方式来完成我想要的事情。

使用惰性模式匹配是可行的,但我可以看到其他编码员可能会对它皱眉。使用读取来查看是否成功解析在编写它时肯定感觉很尴尬。

有更惯用的方法吗?

最佳答案

我建议使用 case 表达式:

main :: IO ()
main = do
  args <- getArgs
  case args of
    [aString, aInteger] | [(n,_)] <- reads aInteger ->
      doStuffWith aString n
    _ -> do
      name <- getProgName
      hPutStrLn stderr $ "usage: " ++ name ++ " <string> <integer>"
      exitFailure

此处使用的防护中的绑定(bind)是 pattern guard ,Haskell 2010 中添加的一项新功能(以及之前常用的 GHC 扩展)。

像这样使用reads是完全可以接受的;它基本上是从无效读取中正确恢复的唯一方法,至少在我们获得 readMaybe 或标准库中的类似内容之前(多年来一直有人建议这样做,但他们已经成为自行车脱落的牺牲品)。使用惰性模式匹配和条件来模拟 case 表达式是不太可接受的:)

另一种可能的替代方案,使用 view patterns扩展名是

case args of
  [aString, reads -> [(n,_)]] ->
    doStuffWith aString n
  _ -> ...

这避免了一次性的aInteger绑定(bind),并使“解析逻辑”接近参数列表的结构。然而,它不是标准的 Haskell(尽管扩展毫无争议)。

对于更复杂的参数处理,您可能需要研究专门的模块 - System.Console.GetOpt位于标准 base 库中,但仅处理选项(不处理参数解析),而 cmdlibcmdargs是更多“全栈”解决方案(尽管我警告您避免使用 cmdargs 的“隐式”模式,因为这是一种粗俗的不纯粹的黑客行为,使语法变得更好一些;但是,“显式”模式应该没问题)。

关于Haskell:解析命令行参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8610277/

相关文章:

haskell 包 : base versus haskel98

python - 处理命令行参数和/或 api 方法参数的模式

haskell - 在 Haskell 中处理嵌套 IO 的惯用方法

c - 查找 C 程序的输出

command-line-arguments - 帕斯卡命令行参数

scala - 如何解析 Scala 中的命令行参数?

perl - Perl 开关的代码内检查

algorithm - 在 Haskell 中具有良好性能的简单循环

haskell - 带有类型家族的歧义类型

haskell - 状态 Monad 在游戏中保存棋盘