美文网首页Haskell
40行Haskell代码的命令行参数解析器

40行Haskell代码的命令行参数解析器

作者: DarkBubble | 来源:发表于2018-07-22 10:19 被阅读1次

40行Haskell代码的命令行解析器

第一步:定义选项结果的数据类型

为了简单起见,考虑三种情况:

  1. 独立选项:即没有任何先导符号,独立存在的选项。
  2. 开关选项:选项即自身,表示开启或者关闭某个功能。
  3. 带值选项:选项是前导符号加上后面的一个参数,表示取一个值(按字符串)

例子:

program -i input.txt -o output.txt s.log -k -v 
  • -i 为带值选项,表示输入文件名
  • -o 为带值选项,表示输出文件名
  • -k-v是开关选项
  • s.log 为独立选项

我们使用Haskell的代数数据类型(ADT)定义上述选项:

data CmdOptionResult = Standalone   {                  value :: String }
                     | OptionSwitch { name  :: String, flag  :: Bool   }
                     | OptionValue  { name  :: String, value :: String } deriving(Eq, Show, Read)

第二步:基本的解析器

  • 开关解析器
parseSwitch _ [] = (Nothing, [])
parseSwitch (sname, lname) args@(arg:as)
    = if arg == lname || arg == sname
      then (Just (OptionSwitch lname True), as)
      else (Nothing, args)
  • 带值选项解析器
parseValue _ [] = (Nothing, [])
parseValue (sname, lname) args@(arg:as)
    = if arg == lname || arg == sname
      then (Just (OptionValue lname (head as)), tail as)
      else (Nothing, args)

解析器组合子

  • 算符 <|>.
parser1 <|> parser2
    = (\as -> let (v1, s1) = parser1 as
                  (v2, s2) = parser2 as
              in  if v1 /= Nothing
                  then (v1, s1)
                  else (v2, s2))
  • 多个选项的解析器的聚合
aggregate ps = foldl1 (<|>) ps
  • 将解释器重复应用在一串参数上
repeat ps = let parser = aggregate ps
                fromJust (Just x) = x
            in  \args -> let (v, s) = parser args
                         in  if args == []
                             then []
                             else if v == Nothing --  match failed, so it is a standalone option value
                                  then (Standalone (head args)):(Util.CmdParser.repeat ps (tail args))

例子

  • 测试例子
parser_lst_example = [ parseSwitch ("-v", "--verbose")
                     , parseValue  ("-i", "--input")
                     , parseValue  ("-o", "--output")
                     , parseValue  ("-m", "--mode")
                     , parseSwitch ("-h", "--help") ]

parser_example = Util.CmdParser.repeat parser_lst_example

args_example_1 = ["-i", "input.txt", "--output", "output.txt", "-v", "-m", "1"]
args_example_2 = ["-h"]
  • 解析结果
parser_example args_example_1
[OptionValue {name = "--input", value = "input.txt"},OptionValue {name = "--output", value = "output.txt"},OptionSwitch {name = "--verbose", flag = True},OptionValue {name = "--mode", value = "1"}]
*Util.CmdParser> parser_example args_example_2
[OptionSwitch {name = "--help", flag = True}]

相关文章

网友评论

    本文标题:40行Haskell代码的命令行参数解析器

    本文链接:https://www.haomeiwen.com/subject/mrrlmftx.html