2

Я пытаюсь разобрать список пар с аппликацией optparse. Разбор одной пары работает, но разбор произвольного числа с использованием комбинатора many терпит неудачу.optparse-applyative: разбор списка пар

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

Отказ от ответственности: У меня нет опыта в использовании продвинутых оппонентов-аппликационных приемов, поэтому я мог бы пропустить что-то очевидное. Читатели: пожалуйста, укажите это, если это так.

Вашей проблема в том, что 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")] 

(Обратите внимание, что в демо-версии выше я обработка провала, возвращая пустой список пара, и учитывая, что нечетное число аргументов должно привести к провалу вас. вам нужно будет внести некоторые изменения, если вы хотите по-другому.)

+0

Благодаря! Я считаю, что поведение «много» действительно запутывает, поскольку я ожидал, что он будет работать больше как Parsec ... Существует ли более синтаксический анализатор командной строки в стиле Parsec? – gedenkt

+0

@gedenkt Не знаю, о чем я знаю. Библиотеки, такие как 'optparse-applative', оптимизированы и специализированы для обработки более обычных вариантов использования аргументов и опций. BTW, еще одна вещь, которую вы могли бы попробовать (хотя я ее не тестировал), указывает настраиваемый формат для ваших пар, как в '{item1, item2}' вместо 'item1 item2'. Я считаю, что пример FluxCapacitor в [readme] (https://hackage.haskell.org/package/optparse-applicative-0.11.0.2) предлагает способ достижения этого с помощью 'optparse-applyative'. – duplode