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