Parsing 为什么在这个解析器序列中会出现类型错误(Erik Meijer的第8课)?

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 -

我正在看Erik Meijer的函数式编程基础系列讲座(还有Graham Hutton的幻灯片)

在中,在定义了类型并引入了一些解析原语(包括and,我将其命名为
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'
    (>>=)    = ...