我一直在阅读有关解析器组合器的教程,我遇到了一个函数,我想在尝试理解时提供一些帮助。
let while_parser = string "while"
我的问题是字符串函数是如何工作的,或者它是如何终止的,比如我做了类似的事情:
parse while_parser "while if"
然后我用它来解析一个字符串,比如说
parse while_parser "test
,它会正确地解析“while”。
但是,如果我尝试Fruit Number_of_Seeds
Rasp 50
Rasp 65
Straw 200
Blue 20
Straw 250
之类的东西,它会返回[]。
我的问题是它是如何失败的?当char c返回一个空列表时会发生什么?
答案 0 :(得分:1)
假设您的Parser
定义如下:
newtype Parser a = Parser { runParser :: String -> [(a,String)] }
然后您的Monad
实例将被定义为:
instance Monad Parser where
return x = Parser $ \input -> [(x, input)]
p >>= f = Parser $ \input -> concatMap (\(x,s) -> runParser (f x) s) (runParser p input)
您想知道char c
在这行代码中失败时会发生什么:
string (c:cs) = do { char c; string cs; return (c:cs) }
首先,让我们去除它:
string (c:cs) = char c >>= \_ -> string cs >>= \_ -> return (c:cs)
现在感兴趣的部分是char c >>= \_ -> string cs
。根据{{1}}的定义以及随后的char
定义,我们发现当satisfy
失败时,最终runParser (char c) input
会评估为[]
。当char c
为>>=
时,请查看p
的定义。 char c
将无法完成任何工作,因为列表将为空!因此,从那时起对concatMap
的任何调用只会遇到一个空列表并将其传递。
参考透明度的一个奇妙之处在于,您可以通过替换定义并手动执行函数应用程序来记下您的表达式并对其进行评估。