но теперь уже продвинулся по Хаскелю и думаю, может есть у этой задачи более красивые "продвинутые решения". Нужно распарсить список опций, которые идут в произвольном порядке. Для каждой опции есть свой парсер и свой тип. Совсем простое решение в таком стиле
unOrd2 :: Alternative f => f a -> f b -> f (a, b)
unOrd2 fa fb = asum
[ (\a b -> (a, b)) <$> fa <*> fb,
(\b a -> (a, b)) <$> fb <*> fa
]
unOrd3 :: Alternative f => f a -> f b -> f c -> f (a, b, c)
unOrd3 fa fb fc = asum
[ (\a (b, c) -> (a, b, c)) <$> fa <*> unOrd2 fb fc,
(\b (a, c) -> (a, b, c)) <$> fb <*> unOrd2 fa fc,
(\c (a, b) -> (a, b, c)) <$> fc <*> unOrd2 fa fb
]
parseTest (unOrd2 pA pB) "ba" -- (a, b)
parseTest (unOrd3 pA pC pB) "abc" -- (a, c, b)
parseTest (unOrd3 pA pC pB) "ab" -- expected 'c'
parseTest (unOrd3 pA (optional pC) pB) "ab" -- (a, Nothing, b)
parseTest (unOrd3 pA (optional pC) pB) "cab" -- (a, Just c, b)
сначала мне не очень показалось, так как нужно этих unOrd кучу написать.
На данный момент у меня это работает через парсер списка: сначала опции парсятся "грубым" парсером, который только понимает, где одна закончилась и новая началась, а затем уже на списке строк вызываются парсеры самих опций. Использование выглядит примерно так:
do -- in Parsec monad
(a, b, c) <- pOpt $ do
-- in OptParser monad
a <- mkOptP pA
b <- mkOptP pB
c <- mkOptP pC
return (a, b, c)
Выглядит, может, и не сильно проще, чем с unOrd-функциями, но более привычно как-то. Но есть проблемы:
1) Сейчас опции стали более сложные и не получается разделить их не распарсив, соответственно в список сложить не получится
2) Приходится играть со стейтом MegaParsec'a, чтобы правильные позиции ошибок внутренних парсеров выдавать
В связи с этим хотелось бы поступить наоборот: сложить парсеры в список и выбирать (альтернативой) первый подошедший, затем его откладывать вместе с результатом и смотреть оставшееся. Можно ли как-то это сделать через HList или что-то типа того?
optparse-applicative не предлагать?
мне нужно внутри MegaParsec'a это запустить как-то И optparse разве не делит всё в список сначала?
а, нет, извиняюсь почему-то не додумался, что надо в код optparse сначала посмотреть может быть и действительно подобное решение сработает
Извините, не удержался (\a b -> (a, b)) <$> fa <*> fb ---> liftA2 (,) fa fb
да, это я, конечно, понимаю :) просто тут суть в том, чтоб как можно единообразнее было написать, чтобы проще было искать общее решение теперь разбираюсь с GADT в optparse-applicative может быть и получится даже то, что хочется
А где нарушилась бы единообразность?
в функциях unOrd. Но это вообще неважно, так как я это специально для примера только набрал
Не уверен что нужно, но можно data PartNP f xs = forall y ys . PartNP (f y) (NP f ys) (forall g . g y -> NP g ys -> NP g xs) parts :: NP f xs -> [PartNP f xs] parts Nil = [] parts (x :* xs) = PartNP x xs (:*):fmap (\(PartNP y ys inj) -> PartNP y (x :* ys) \p (q :* qs) -> q :* inj p qs) (parts xs) unordered :: Alternative f => NP f xs -> f (NP I xs) unordered Nil = pure Nil unordered xs = asum $ parts xs <&> \(PartNP y ys inj) -> liftA2 (inj . I) y (unordered ys) test :: Parsec Void Text (NP I [Text, Text, Int, [Double]]) test = unordered $ "foo" :* "bar" :* decimal :* between "[" "]" (float `sepEndBy` ",") :* Nil ordNub $ parseMaybe (test <* eof) . mconcat <$> permutations ["foo", "bar", "42", "[12.34,56.78]"] [Just (I "foo" :* I "bar" :* I 42 :* I [12.34,56.78] :* Nil)] Но про перформанс этого мне конечно даже думать страшно
Какой пример для 1)?
Обсуждают сегодня