是否可以使用applicative表达chainl1?

时间:2011-10-10 23:00:07

标签: parsing haskell parsec

是否可以从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

2 个答案:

答案 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)

在解析opp对时,会立即应用结果,但由于pop的右操作数,因此需要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)