来自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
。
答案 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)。我有意模仿我的术语中的类型变量,使其更加明显。