Is it possible to express the chainl1
combinator from Parsec not using the Monad instance defined by parsec?
chainl1 p op =
do x <- p
rest x
where
rest x = do f <- op
y <- p
rest (f x y)
<|> return x
Yes, it is:
chainl1 p op = foldl (flip ($)) <$> p <*> many (flip <$> op <*> p)
The idea is that you have to parse p (op p)*
and evaluate it as (...(((p) op p) op p)...)
.
It might help to expand the definition a bit:
chainl1 p op = foldl (\x f -> f x) <$> p <*> many ((\f y -> flip f y) <$> op <*> p)
As the pairs of op
and p
are parsed, the results are applied immediately, but because p
is the right operand of op
, it needs a flip
.
So, the result type of many (flip <$> op <*> p)
is f [a -> a]
. This list of functions is then applied from left to right on an initial value of p
by foldl
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With