optparse-applicative:解析对列表
optparse-applicative: parsing list of pairs
我正在尝试使用 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
有什么想法吗?
免责声明:我没有使用高级 optparse-applicative 技巧的经验,所以我可能遗漏了一些明显的东西。读者:如有请指出
你的问题是 many
所做的是(在手工波浪描述中)将解析器应用于输入的每个块,在这种情况下,块由单独的参数组成,然后收集结果。所以 many pairParser
将 pairParser
应用到 ["one"]
,然后应用到 ["two"]
,并且两个解析都失败了。既然如此,您可以将 execParserPure
替换为一个函数,该函数以适当的方式对参数进行分块并相应地调整程序的其余部分,或者(我怀疑是更容易的选择)放弃 pairParser
和只需 post- 处理已解析的参数,如:
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")]
(请注意,在上面的演示中,我通过返回一个空的对列表来处理失败,并考虑到奇数个参数会导致失败。如果你想要一个,你需要做一些调整不同的行为。)
许多人和一些人对旧版本的 optparse 有点过于渴望,并且在允许进一步的选项之前要求整个构造在单个选项之后成功。
我改变了很多人的逻辑,所以他们在如何使用超过很多和一些的选项方面更加懒惰。你可以看到变化和逻辑 here .
我正在尝试使用 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
有什么想法吗?
免责声明:我没有使用高级 optparse-applicative 技巧的经验,所以我可能遗漏了一些明显的东西。读者:如有请指出
你的问题是 many
所做的是(在手工波浪描述中)将解析器应用于输入的每个块,在这种情况下,块由单独的参数组成,然后收集结果。所以 many pairParser
将 pairParser
应用到 ["one"]
,然后应用到 ["two"]
,并且两个解析都失败了。既然如此,您可以将 execParserPure
替换为一个函数,该函数以适当的方式对参数进行分块并相应地调整程序的其余部分,或者(我怀疑是更容易的选择)放弃 pairParser
和只需 post- 处理已解析的参数,如:
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")]
(请注意,在上面的演示中,我通过返回一个空的对列表来处理失败,并考虑到奇数个参数会导致失败。如果你想要一个,你需要做一些调整不同的行为。)
许多人和一些人对旧版本的 optparse 有点过于渴望,并且在允许进一步的选项之前要求整个构造在单个选项之后成功。
我改变了很多人的逻辑,所以他们在如何使用超过很多和一些的选项方面更加懒惰。你可以看到变化和逻辑 here .