Parsing 为什么在这个解析器序列中会出现类型错误(Erik Meijer的第8课)?
我正在看Erik Meijer的函数式编程基础系列讲座(还有Graham Hutton的幻灯片) 在中,在定义了类型并引入了一些解析原语(包括and,我将其命名为Parsing 为什么在这个解析器序列中会出现类型错误(Erik Meijer的第8课)?,parsing,haskell,types,monads,Parsing,Haskell,Types,Monads,我正在看Erik Meijer的函数式编程基础系列讲座(还有Graham Hutton的幻灯片) 在中,在定义了类型并引入了一些解析原语(包括and,我将其命名为return')之后,Erik给出了如何使用do语法将其解析器组合成一个序列的示例: type Parser a = String -> [(a,String)] item :: Parser Char item = \inp -
return'
)之后,Erik给出了如何使用do语法将其解析器组合成一个序列的示例:
type Parser a = String -> [(a,String)]
item :: Parser Char
item = \inp -> case inp of
[] -> []
(x:xs) -> [(x,xs)]
return' :: a -> Parser a
return' v = \inp -> [(v,inp)]
p :: Parser (Char,Char)
p = do x <- item
item
y <- item
return' (x,y)
type解析器a=String->[(a,String)]
项::解析器字符
item=\inp->case inp of
[] -> []
(x:xs)->[(x,xs)]
return'::a->Parser a
返回'v=\inp->[(v,inp)]
解析器(Char,Char)
p=dox[(字符,字符,字符串)]
实际类型:解析器([(字符,字符串)],[(字符,字符串)])
在“do”块的stmt中:返回(x,y)
在表达式中:
do{x此错误消息有点让人困惑,因为GHC将您的解析器
类型解压缩到其String->[(a,String)]
的定义中。如果我们撤消此转换,它将变得更有意义:
Expected type: Parser (Char, Char)
Actual type: Parser ([(Char, String)], [(Char, String)])
现在它开始变得更有意义了。它看起来是这样的:您将两次调用的结果带到解析器Char
(即[(Char,String)]
)中,然后将它们当作正常的Char
使用。错误发生在第15行,这是您对return'
的调用:
return' (x, y)
这告诉我们,x
和y
是两个有问题的结果
您拥有的do块正在使用monad实例处理String->b
类型的函数;其作用是通过串接输入(String
)将它们组合成一个更大的String->b
函数通过所有函数。类似于xb
函数的一行,同时维护所有管道以通过字符串
参数。不幸的是,项
是一个解析器字符
,这意味着b
实际上是一个[(字符,字符串)]
而不仅仅是一个字符
正确解析需要这个额外的返回结构。字符串
表示解析字符
(或您正在解析的任何内容)时未使用的其余输入,整个内容是一个列表,因为可以有多种可能的方法来有效解析需要处理的部分输入
要使这项工作正常进行,您必须有一些方法来处理这个额外的结构。但是,由于我没有学习课程或观看讲座,我不知道它是什么。您可以定义自己的monad实例,而不是依赖内置的函数实例,但您可能还没有深入到类中来完成这项工作urself或Meijer可能使用非标准库来避免此问题,在这种情况下,您需要确保您的设置与类所期望的相符。问题在于您定义的p
中的do符号没有使用您希望它使用的单子
我可能错了,但看起来p
使用的是阅读器monad的一个版本
如果使用此定义,您将看到x
和y
不是Char
值,而是类型[(Char,String)]
:
下面是一篇关于如何使用newtype
定义解析器monad实例的好博文:谢谢;这更有意义。您的句子中缺少一个词:“您可以自己定义monad实例[…]”。您的意思是“定义”吗?另外,我不认为Meijer在我的问题中使用了比代码更奇特的东西。我很惊讶他的代码没有像广告上所说的那样工作。@Jubobs:哦,是的,那是一个拼写错误。现在已经修复了。我不确定他在做什么,我现在也不能看讲座,但是如果他定义了自己的返回值
(与您的返回“
”不同的是,使用该确切名称),他可能在做一些特别的事情。但我真的不知道。据我所知,你的答案是正确的。因为解析器a
不是Monad
的派生实例,所以应用的do语法不是作者所期望的。它提到了一个问题,我相信这就是我遇到的问题。一切都按照经验进行ted,如果我不使用do语法,而是使用desugared语法,使用Hutton对>=
的定义。作者还发布了一篇文章,其中解析器a
是Monad
的一个实例。我不知道答案,但我相信这些讲座是与名为Text.ParserCombinators.HuttonMeijer的模块一起进行的安装这个我可以像在讲座中一样,除了键入papply而不是parse:///////Prelude>:m Text.ParserCombinators.HuttonMeijer/////Prelude Text.ParserCombinators.HuttonMeijer>/////Prelude Text.ParserCombinators.HuttonMeijer>papply项“abc////////[a',“bc
return' (x, y)
import Debug.Trace
p :: Parser (Char,Char)
p = do x <- item
y <- item
let foo = trace ("x = " ++ show x) 'a'
bar = trace ("y = " ++ show y) 'b'
return' (foo,bar)
test = p "qwe"
newtype Parser a = Parser { parse :: String -> [ (a,String) ] }
instance Monad Parser where
return = Parser . return'
(>>=) = ...