Disclaimer: I have no experience of doing advanced optparse-applicative tricks, so I might be missing something obvious. Readers: please point it out if that's the case.
Your problem is that what many
does is (in a hand-wavy description) to apply the parser to each chunk of the input, with the chunks in this case consisting of individual arguments, and then collect the results. So many pairParser
applies pairParser
to ["one"]
and then to ["two"]
, and both parses fail. That being so, you might either replace execParserPure
with a function that chunks the arguments in an appropriate way and adjust the rest of the program accordingly, or (what I suspect is the easier choice) abandon pairParser
and just post-process the parsed arguments, as in:
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")]
(Note that in the demo above I'm handling failure by returning an empty list of pairs, and considering that an odd number of arguments should lead to failure. You'll need to do some adjustments if you want a different behaviour.)