Haskell:解析命令行参数 [英] Haskell: Parsing command line arguments

查看:139
本文介绍了Haskell:解析命令行参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



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

我这样实现它:

  main = do 
args @(〜(aString:aInteger:[]))< - getArgs
解析@(〜[(n,_)])=读取aInteger
如果长度args / = 2 || L.null解析
然后执行
名称< - getProgName
hPutStrLn stderr $usage:++ name ++< string>< integer>
exitFailure
else do
doStuffWith aString n

,这是我第一次真正在Haskell中使用命令行参数,所以我不确定这是否是一种非常尴尬和难以理解的方式来做我想做的事情。



使用懒惰模式匹配工作,但我可以看到它是如何被其他编码人员所诟病的。使用阅读来看看我是否成功解析了它,这在写作时肯定会感到尴尬。



有没有更习惯性的方法来做到这一点?

解决方案

我建议使用个案表达式:

  main :: IO()
main = do
args< - getArgs

[aString, aInteger] | [(n,_)]< - 读取整数 - >
doStuffWith aString n
_ - > do
name< - getProgName
hPutStrLn stderr $usage:++ name ++< string>< integer>
exitFailure

这里使用的守卫中的绑定是模式守护者,这是Haskell 2010中添加的一项新功能(以及之前的常用GHC扩展)。

使用读取这样是完全可以接受的;它基本上是正确地从无效读取中恢复的唯一方法,至少直到我们在标准库中获得 readMaybe 或其它类似的东西(已经有提议通过几年,但他们已经陷入了猎杀)。使用懒惰模式匹配和条件来模拟 case 表达式是不太可接受的:)

另一种可能的替代方法是使用查看模式的扩展名是

  
的情况参数[aString,reads - > [(n,_)]] - >
doStuffWith aString n
_ - > ...

这样可以避免一次性使用 aInteger 绑定,并保持解析逻辑接近参数列表的结构。然而,这不是标准的Haskell(尽管扩展并不存在争议)。



对于更复杂的参数处理,您可能需要查看专门的模块 - System.Console.GetOpt 是标准的 base 库,但只处理选项(不是参数解析),而 cmdlib cmdargs 是更全面的解决方案(尽管我警告您避免使用cmdargs的隐式模式,因为它是一个严重的不纯的破解让语法变得更好;然而,Explicit模式应该没问题)。


This more of a style question, rather than a how to.

So I've got a program that needs two command line arguments: a string and an integer.

I implemented it this way:

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

While this works, this is the first time I've really used command line args in Haskell, so I'm not sure whether this is a horribly awkward and unreadable way to do what I want.

Using lazy pattern matching works, but I could see how it could be frowned upon by other coders. And the use of reads to see if I got a successful parse definitely felt awkward when writing it.

Is there a more idiomatic way to do this?

解决方案

I suggest using a case expression:

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

The binding in a guard used here is a pattern guard, a new feature added in Haskell 2010 (and a commonly-used GHC extension before that).

Using reads like this is perfectly acceptable; it's basically the only way to recover properly from invalid reads, at least until we get readMaybe or something of its ilk in the standard library (there have been proposals to do it over the years, but they've fallen prey to bikeshedding). Using lazy pattern matching and conditionals to emulate a case expression is less acceptable :)

Another possible alternative, using the view patterns extension, is

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

This avoids the one-use aInteger binding, and keeps the "parsing logic" close to the structure of the argument list. However, it's not standard Haskell (although the extension is by no means controversial).

For more complex argument handling, you might want to look into a specialised module — System.Console.GetOpt is in the standard base library, but only handles options (not argument parsing), while cmdlib and cmdargs are more "full-stack" solutions (although I caution you to avoid the "Implicit" mode of cmdargs, as it's a gross impure hack to make the syntax a bit nicer; the "Explicit" mode should be just fine, however).

这篇关于Haskell:解析命令行参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆