Parsec 简单解析器导致错误 "Non type-variable argument in the constraint: Stream s m Char"

Parsec simple parser results in error "Non type-variable argument in the constraint: Stream s m Char"

假设我只想创建自己的解析器,它与 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

我该如何解决?我应该包括任何其他进口商品吗?谢谢

Parsec 解析器由于其灵活性而具有相当复杂的类型。您可以通过两种方式解决此问题:

  1. {-# Language FlexibleContexts #-} 放在源文件的顶部。这个 pragma 告诉 GHC 做一些额外的类型推断。

  2. (推荐)给char1一个显式类型。

    char1 :: Char -> Parsec String () Char   
    char1 c = char c
    

这是推荐的,因为您应该始终为任何顶级声明指定显式类型。如果你不这样做,那么所有编译器都会告诉你代码中某处存在类型不匹配(它会告诉你在哪里发现了矛盾,但不太可能是错误所在)。使用显式类型声明,编译器可以缩小范围。

在这种情况下,Parsec 将 Parsec 类型定义为

type Parsec s u = ParsecT s u Identity

您将从错误消息中认出 ParsecTParsecT 是一个 monad 转换器:当它识别文本时,它允许您让解析器在其他 monad(如 IO)中执行操作。在这种情况下,我们只需要一个解析器,所以我们使用 Identity monad,它什么都不做。

s 参数是输入流。在这种情况下,我们会说解析器正在从 String.

获取输入

u参数是一个状态。这允许你做一些事情,比如在你遇到它们时在符号 table 中记录变量名。在这种情况下,我们不使用状态,所以它只是 ().

如果您正在编写一个真正的解析器,那么您通常会定义自己的类型同义词,例如

type FooParser a = Parsec Text FooState a

char1 :: Char -> FooParser Char
char1 = char