我正在尝试使用Parsec库来解析Token
值列表。我想使用Text.Parsec.Prim中的token
函数来匹配单个值。看起来这应该有效:
type TokenParser a = Parsec [Token] () a
mytoken :: (Token -> Bool) -> TokenParser Token
mytoken test = token showTok posFromTok testTok
where -- and so on
这会产生编译错误:
No instance for (Stream [Token] Identity Token)
arising from a use of `Prim.token'
Possible fix:
add an instance declaration for (Stream [Token] Identity Token)
好的,让我们更改mytoken:
mytoken :: Stream [Token] Identity Token => (Token -> Bool) -> TokenParser Token
在我们添加{-# LANGUAGE FlexibleContexts #-}
扩展名后,这是有效的。
发生了什么事?首先,Text.Parsec.Prim中的Stream
类定义将Monad m => Stream [tok] m tok
作为其中一个实例。那个实例不应该Stream [Token] Identity Token
已经涵盖了吗?其次,这甚至会限制什么呢? mytoken
的类型中没有要约束的类型变量。
更糟糕的是,当我在另一个函数中使用我的新“约束”mytoken
时,我得到完全相同的错误,No instance for (Stream [Token] Identity Token) arising from...
它实际上需要使用相同的,看似无操作的类型试图调用mytoken
的函数类型的约束。
如果有人能帮我解释这种类型约束的作用,我会非常感激。
答案 0 :(得分:9)
以下文件是我可以构建的最小的文件,可以重现您的问题。 (将来,您应该自己为我们创建这样的文件。)
import Text.Parsec.Prim
data Token
type TokenParser a = Parsec [Token] () a
mytoken :: (Token -> Bool) -> TokenParser Token
mytoken test = token showTok posFromTok testTok
showTok = undefined
posFromTok = undefined
testTok = undefined
将导入从Text.Parsec.Prim
更改为Text.Parsec
可修复错误。 (适当的实例在Text.Parsec.String
中定义,由Text.Parsec.Prim
导入。)您还会问为什么此更改会使其编译但不起作用:
mytoken :: Stream [Token] Identity Token => (Token -> Bool) -> TokenParser Token
一般规则是“C => T”类型说:“你可以使用这个东西就像它是T一样,前提是你可以证明满足约束条件C”。所以给mytoken
你所做的类型说要等到mytoken
被使用,好像它是一个普通的(Token -> Bool) -> TokenParser Token
,并且一旦这样,就尽快履行显示该义务的义务Stream [Token] Identity Token
成立。由于您仍未导入相应的实例,因此无法履行该义务并提出投诉。