来自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
我做错了什么?
答案 0 :(得分:6)
您误解了文档,Text.Parsec.Token
导出的lexeme
是GenTokenParser s u m
的字段,因此类型为
lexeme :: GenTokenParser s u m -> ParsecT s u m a -> ParsecT s u m a
并且您未在GenTokenParser
中提供lexeme constant
参数。
您需要先从GenLanguageDef
(通常使用makeTokenParser
)创建GenTokenParser
,然后使用其lexeme
字段。
答案 1 :(得分:2)
lexeme
函数是GenTokenParser
生成的makeTokenParser
解析器记录的访问者,因此您需要将其应用于此类记录以获取它。一种常见的方法是使用记录通配符,例如
{-# LANGUAGE RecordWildCards #-}
import qualified Text.Parsec.Token as Tok
Tok.TokenParser { .. } = Tok.makeTokenParser {- language definition -}
这会将lexeme
和所有其他解析器带入已应用于记录的范围,因此您可以像尝试一样使用它。