假设我只想创建自己的解析器,该解析器与Parsec中的char
完全相同,但是在运行时
import Text.Parsec
char1 c = char c
它给了我
? Non type-variable argument in the constraint: Stream s m Char
(Use FlexibleContexts to permit this)
? When checking the inferred type
char1 :: forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Cha
我该如何解决?我还应该包括其他进口商品吗?谢谢
答案 0 :(得分:2)
Parsec解析器由于其灵活性而具有相当复杂的类型。您可以通过两种方式解决此问题:
将{-# Language FlexibleContexts #-}
放在源文件的顶部。这种语用告诉GHC做一些额外的类型推断。
(推荐)给char1一个显式类型。
char1 :: Char -> Parsec String () Char
char1 c = char c
建议这样做,因为您应始终为任何顶级声明提供显式类型。如果您不这样做,那么所有编译器都可以告诉您代码中某处存在类型不匹配(它将告诉您它在哪里找到了矛盾,但这不太可能是错误所在)。使用显式类型声明,编译器可以缩小范围。
在这种情况下,Parsec将Parsec
类型定义为
type Parsec s u = ParsecT s u Identity
您将从错误消息中识别出ParsecT
。 ParsecT
是monad转换器:它使解析器在识别文本时让解析器在其他monad(例如IO)中执行操作。在这种情况下,我们只需要一个解析器,因此我们使用Identity
monad,它什么都不做。
s
参数是输入流。在这种情况下,我们将说解析器正在从String
获取输入。
u
参数是一个状态。这使您可以在遇到变量时做一些事情,例如在符号表中记录变量名。在这种情况下,我们不使用状态,因此仅使用()
。
如果您正在编写一个真正的解析器,则通常会定义自己的类型同义词,例如
type FooParser a = Parsec Text FooState a
char1 :: Char -> FooParser Char
char1 = char