Так что я собираюсь писать сложный парсер, используя только аппликативный (рассматриваемый парсер даже не реализует Monad).Борьба с аппликативным разбором
Для тривиальных парсеров это довольно просто. Для нетривиальных ... не так много. Аппликативный интерфейс, похоже, сильно заставляет вас писать все в стиле без ограничений. С этим очень сложно справиться.
Рассмотрит, например:
call = do
n <- name
char '('
trim
as <- sepBy argument (char ',' >> trim)
char ')'
trim
char '='
r <- result
return $ Call {name = n, args = as, result = r}
Теперь давайте попробуем написать, что с помощью Аппликативного:
call =
(\ n _ _ as _ _ _ _ r -> Call {name = n, args = as, result = r}) <$>
name <*>
char '(' <*>
trim <*>
sepBy argument (const const() <$> char ',' <*> trim) <*>
char ')' <*>
trim <*>
char '=' <*>
trim <*>
result
Аппликативных имеет заставил меня поставить переменные привязки очень далеко от того, где фактического парсер. (Например, попробуйте подтвердить, что as
на самом деле связан с sepBy argument ...
, это совсем не просто, чтобы убедиться, что я не получил неправильный подсчет из _
моделей!)
Другого очень неинтуитивное то, что <*>
применяет функцию к значение, но *>
и <*
- это просто чистое упорядочение. Это взяло для возрастов, чтобы обернуть мой разум вокруг. Имена разных методов сделали бы это намного, намного яснее. (Но Монада, кажется, схватил >>
и <<
, к сожалению.) Кажется, что они могут быть сложены, давая такие вещи, как
exit =
"EXIT:" *>
trim *>
name <*
char '(' <*
trim <*
char ')' <*
trim
Это довольно неочевидным, что вы можете сделать это. И, для меня, этот код действительно не ужасно читабельен. Что еще более важно, я до сих пор не понял, как вы занимаетесь сбором нескольких значений при отбрасывании нескольких других значений.
В целом, я нахожусь желающим, чтобы я мог просто использовать нотацию! Мне действительно не нужно изменять эффекты, основанные на предыдущих результатах; Я не нужно власти Монады. Но обозначение настолько читаемо. (Я продолжаю задаваться вопросом, действительно ли возможно реализовать это: можете ли вы синтаксически сказать, когда конкретный блок do может быть механически преобразован в аппликативный?)
Кто-нибудь знает об этом? В частности, как я могу переместить привязки переменных ближе к парсеру, к которому они привязаны?
Я предполагаю, что ждет ['Applicative-Do'] (https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo) слишком сложно для некоторых людей;) –
Я не думаю' << 'существует, по крайней мере, не в' base'. – Rufflewind
@BartekBanachewicz Applicative-do ... Запрос функции уже существует. Я думаю, это правда; если вы можете думать об этом, это уже где-то в Интернете. – MathematicalOrchid