实现`Applicative Parser`的应用功能

时间:2014-12-30 01:32:35

标签: parsing haskell

来自Brent Yorgey的2013 Penn class,在获得有关定义Functor Parser的帮助后,我试图制作Applicative Parser

--p1 <*> p2 represents the parser which first runs p1 (which will
--consume some input and produce a function), then passes the
--remaining input to p2 (which consumes more input and produces
--some value), then returns the result of applying the function to the
--value

这是我的尝试:

instance Applicative (Parser) where
  pure x                    = Parser $ \_ -> Just (x, [])
  (Parser f) <*> (Parser g) = case (\ys -> f ys) of Nothing      -> Parser Nothing
                                                    Just (_, xs) -> Parser $ g xs

但是,我在apply (<*>)定义上遇到了编译时错误。

直观地说,我相信使用<*>可以实现AND功能。

如果我有foo解析器和bar解析器,那么我应该可以使用apply <*>说:foo后跟bar }。换句话说,foobar的输入应该成功匹配,而foobip则不会。它会在第二个解析器上失败。

但是,我认为类型是:

Parser (a -> b) -> Parser a -> Parser b

所以,这让我觉得我的直觉并不完全正确。

请给我一个提示,以指导我了解如何实施apply

1 个答案:

答案 0 :(得分:7)

您的代码基于对Parser的误解。别担心,几乎每个人都犯了这个错误。

newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }

让我们分解这意味着什么。

String -> Maybe (a, String)
[1]       [2]   [3] [4]

[1]:我拿一个字符串并返回Maybe (a, String)

[2]:我可能无法成功将输入解析为所需的数据类型

[3]:我正在将字符串解析为

的所需类型

[4]:在消耗了解析a所需的数据量之后的剩余输入

Parser是一个函数文本输入到可能一个值的元组和文本的其余部分。 Parser强调元组,否则您将无法使用解析器。只是元组中的数据。

我不会告诉你如何实施<*>,其他任何人都不应该因为它会剥夺你的体验。

但是,我会给你pure,以便你了解基本模式:

 pure a = Parser (\s -> Just (a, s))

请参阅?它是s - &gt;的函数。也许(a,s)。我有意模仿我的术语中的类型变量,使其更加明显。