2

我试图用optparse-applicative解析列表对。解析单个对可行,但使用many组合子失败任意解析。optparse-applicative:解析列表对

import   Options.Applicative 

pairParser = (,) <$> argument str (metavar "s1") 
       <*> argument str (metavar "s2") 

testParser p = getParseResult . execParserPure (prefs idm) 
    (info (helper <*> p) fullDesc) 

main = do 
    print $ testParser pairParser ["one", "two"] 
    print $ testParser (many pairParser) [] 
    print $ testParser (many pairParser) ["one", "two"] 
    print $ testParser (many pairParser) ["one", "two", "three", "four"] 

输出:

Just ("one","two") <- good 
Just []    <- still good 
Nothing    <- does not work 
Nothing    <- also does not work 

任何想法?

回答

1

免责声明:我没有做高级optparse-applicative技巧的经验,所以我可能会失去一些明显的东西。读者:请指出,如果是这样的话。

您的问题是,many所做的是(在手动描述中)将解析器应用于每个输入块,在这种情况下块由单个参数组成,然后收集结果。因此,many pairParserpairParser应用于["one"],然后应用到["two"],并且两个解析都失败。既然如此,你可以用一个函数来代替execParserPure,这个函数能够以合适的方式对参数进行分块并相应地调整程序的其余部分,或者(我怀疑是更容易的选择)放弃pairParser并且只是后处理分析的参数,如:

pairArgs :: [a] -> [(a, a)] 
pairArgs = noLeftover . foldr pairNext (Nothing, []) 
    where 
    noLeftover (m, ps) = case m of 
     Nothing -> ps 
     _  -> [] 
    pairNext x (m, ps) = case m of 
     Just y -> (Nothing, (x, y) : ps) 
     Nothing -> (Just x, ps) 

manyPairsParser :: Parser [(String, String)] 
manyPairsParser = pairArgs <$> many (argument str (metavar "s1 s2..")) 
GHCi> testParser manyPairsParser [] 
Just [] 
GHCi> testParser manyPairsParser ["foo"] 
Just [] 
GHCi> testParser manyPairsParser ["foo","bar"] 
Just [("foo","bar")] 
GHCi> testParser manyPairsParser ["foo","bar","baz"] 
Just [] 
GHCi> testParser manyPairsParser ["foo","bar","baz","quux"] 
Just [("foo","bar"),("baz","quux")] 

(请注意,在演示上面我处理故障通过返回对空列表,并考虑奇数的参数应该导致失败你”。如果你想要不同的行为,你需要做一些调整。)

+0

谢谢!我发现'many'的行为真的让人困惑,因为我预计它更像Parsec ......是否存在更多的Parsec风格的命令行解析器? – gedenkt

+0

@gedenkt不是我所知道的。像optparse-applicative这样的库是精简的,专门用来处理更常见的参数和选项传递用例。顺便说一句,你可能尝试的另一件事(虽然我没有测试过)为你的对指定了一个自定义格式,就像'{item1,item2}'而不是'item1 item2'一样。我相信[readme](https://hackage.haskell.org/package/optparse-applicative-0.11.0.2)中的FluxCapacitor示例提供了一种使用'optparse-applicative'实现该功能的方法。 – duplode