1

来自Text.Parsec.Token

lexeme p = do { x <- p; whiteSpace; return x }

似乎 lexeme 采用解析器 p 并提供与 p 具有相同行为的解析器,除了它还跳过所有尾随空格。正确的?

那么为什么以下不起作用:

constant :: Parser Int
constant = do
    digits <- many1 digit
    return (read digits)

lexConst :: Parser Int
lexConst = lexeme constant

最后一行导致以下错误消息:

Couldn't match expected type `ParsecT
                                String () Data.Functor.Identity.Identity Int'
            with actual type `ParsecT s0 u0 m0 a0 -> ParsecT s0 u0 m0 a0'
Expected type: Parser Int
  Actual type: ParsecT s0 u0 m0 a0 -> ParsecT s0 u0 m0 a0
In the return type of a call of `lexeme'
In the expression: lexeme constant

我究竟做错了什么?

4

2 回答 2

6

您误解了文档,lexeme导出的 fromText.Parsec.Token是 a 的字段GenTokenParser s u m,所以类型是

lexeme :: GenTokenParser s u m -> ParsecT s u m a -> ParsecT s u m a

并且您没有GenTokenParserlexeme constant.

您需要GenTokenParser先从 a GenLanguageDef(通常使用makeTokenParser)创建一个才能使用其lexeme字段。

于 2013-05-06T16:25:28.943 回答
2

lexeme函数是GenTokenParser由 生成的解析器记录的访问器makeTokenParser,因此您需要将其应用于这样的记录才能获取它。一种常见的方法是使用记录通配符,例如

{-# LANGUAGE RecordWildCards #-}

import qualified Text.Parsec.Token as Tok

Tok.TokenParser { .. } = Tok.makeTokenParser {- language definition -}

这会将lexeme所有其他解析器带入已应用于记录的范围内,因此您可以像尝试那样使用它。

于 2013-05-06T16:26:33.680 回答