是否可以从Parsec表达chainl1
组合子而不使用parsec定义的Monad实例?
chainl1 p op =
do x <- p
rest x
where
rest x = do f <- op
y <- p
rest (f x y)
<|> return x
答案 0 :(得分:5)
是的,它是:
chainl1 p op = foldl (flip ($)) <$> p <*> many (flip <$> op <*> p)
您的想法是,您必须解析p (op p)*
并将其评估为(...(((p) op p) op p)...)
。
稍微扩展定义可能会有所帮助:
chainl1 p op = foldl (\x f -> f x) <$> p <*> many ((\f y -> flip f y) <$> op <*> p)
在解析op
和p
对时,会立即应用结果,但由于p
是op
的右操作数,因此需要flip
1}}。
因此,many (flip <$> op <*> p)
的结果类型为f [a -> a]
。然后,这个函数列表从左到右应用p
的初始值foldl
。
答案 1 :(得分:0)
丑陋但等效的Applicative
定义:
chainl1 p op =
p <**>
rest
where
rest = flip <$> op <*>
p <**>
pure (.) <*> rest
<|> pure id
这个Applicative形式'链'x
部分适用于他们的右侧参数,而不是将左侧参数op
明确地传递给右侧op
。 (因此flip <$> op <*> p
)通过提升的组合子(.)
,然后通过p
将最左边的(<**>)
应用于生成的rest :: Alternative f => f (a -> a)
。