非类型变量约束

时间:2014-04-04 05:02:41

标签: haskell parsec

我正在尝试使用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的函数类型的约束。

如果有人能帮我解释这种类型约束的作用,我会非常感激。

1 个答案:

答案 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成立。由于您仍未导入相应的实例,因此无法履行该义务并提出投诉。