4

我正在尝试使用 optparse-applicative 解析对列表。解析单个对有效,但使用many组合器解析任意多个会失败。

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

有任何想法吗?

4

2 回答 2

3

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

您的问题是many(在手动描述中)将解析器应用于输入的每个块,在这种情况下,块由单个参数组成,然后收集结果。所以many pairParser适用pairParser["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")]

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

于 2015-07-20T20:47:52.767 回答
3

许多和一些在旧版本的 optparse 中有点过于急切,并且在允许更多选项之前需要在单个选项之后整个构造成功。

我改变了许多人的逻辑,因此他们在如何使用许多选项时更加懒惰。您可以在此处查看更改和逻辑。

于 2018-06-14T21:56:37.947 回答