I don't understand how to use the lexeme function
我已经看到了上述问题,但我仍然不明白。
例如,the documentation中的示例也不起作用。
mainParser = do{ whiteSpace
; ds <- many (lexeme digit)
; eof
; return (sum ds)
}
答案 0 :(得分:5)
免责声明:我还没有使用Parsec
。话虽如此,lexeme
是GenTokenParser s u m
的字段。如果你在GHCi中检查它的类型,你最终会得到
lexeme :: GenTokenParser s u m -> ParsecT s u m a -> ParsecT s u m a
因此,您已经需要一个通用的令牌解析器,您可以使用makeTokenParser
创建它。后者的类型为:
makeTokenParser
:: Stream s m Char =>
Text.Parsec.Token.GenLanguageDef s u m
-> Text.Parsec.Token.GenTokenParser s u m
它需要一个语言定义并返回一个令牌解析器。由于您没有考虑任何特定语言,因此可以使用emptyDef
中的Text.Parsec.Language
。请注意,whiteSpace
也需要GenTokenParser
。最后,在此设置中,您最终会得到ds :: [Char]
,因此您需要先使用digitToInt
中的Data.Char
,然后才能真正总结您的数字:
import Text.Parsec
import Text.Parsec.Token (lexeme, makeTokenParser, whiteSpace)
import Text.Parsec.Language (emptyDef)
import Data.Char (digitToInt)
lexer = makeTokenParser emptyDef
mainParser = do{ whiteSpace lexer
; ds <- many (lexeme lexer digit)
; eof
; return (sum . map digitToInt $ ds)
}
main = do
putStrLn "Please give some digits (whitespaces are ignored)"
line <- getLine
case parse mainParser "" line of
Right n -> putStrLn $ "Sum of digits is " ++ show n
Left _ -> putStrLn $ "Couldn't parse your line"
示例输出:
*Main> :main Please give some digits 7 8 91 72 3945 01 92 Sum of digits is 67 *Main> :main Please give some digits abc 1 Couldn't parse your line
答案 1 :(得分:4)
免责声明:我不是Haskell或解析专家。我已经修改了上面的代码
import Text.Parsec
import qualified Text.Parsec.Token as T
import Text.Parsec.String ( Parser )
import Text.Parsec.Language (haskellDef)
lexer = T.makeTokenParser haskellDef
whiteSpace :: Parser ()
whiteSpace = T.whiteSpace lexer
lexeme = T.lexeme lexer
mainParser = do whiteSpace
ds <- many digit
eof
return ds
让我们运行上面的代码。
Mukeshs-MacBook-Pro:Compilers mukeshtiwari$ ghci stmp.hs
GHCi, version 7.6.1: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main ( stmp.hs, interpreted )
Ok, modules loaded: Main.
*Main> parse mainParser "" "1"
Loading package array-0.4.0.1 ... linking ... done.
Loading package deepseq-1.3.0.1 ... linking ... done.
Loading package bytestring-0.10.0.0 ... linking ... done.
Loading package transformers-0.3.0.0 ... linking ... done.
Loading package mtl-2.1.2 ... linking ... done.
Loading package text-0.11.2.3 ... linking ... done.
Loading package parsec-3.1.3 ... linking ... done.
Right "1"
*Main> parse mainParser "" "12"
Right "12"
*Main> parse mainParser "" "123"
Right "123"
*Main> parse mainParser "" " 123"
Right "123"
*Main> parse mainParser "" " 123"
Right "123"
*Main> parse mainParser "" " 123"
Right "123"
到目前为止,每件事情都很好看。现在我们应该尝试更多的输入。
*Main> parse mainParser "" "123 "
Left (line 1, column 4):
unexpected ' '
expecting digit or end of input
糟糕!我们的解析器出了点问题。你能发现输入的差异吗?现在,如果你发现了差异,你可以看到在第二种情况下最后有空间,但是为什么这个解析器能够在数字文字之前处理空格?记住whiteSpace函数,它会在数字文字之前占用所有空格,并将剩余的输入提供给其余代码(多位数),这些代码在遇到非数字之前会继续消耗尽可能多的数字文字。输入的其余部分(在我们的例子中是剩余空间)再次传递给eof,因此我们的解析器会抱怨空间。在阅读数字文字时,我们可以忽略这些空格吗?我们知道whiteSpace会占用零个或多个空格,因此请添加我们的代码(忽略&lt; *一会儿)。
import Text.Parsec
import qualified Text.Parsec.Token as T
import Text.Parsec.String ( Parser )
import Text.Parsec.Language (haskellDef)
import Control.Applicative ( (<*) )
lexer = T.makeTokenParser haskellDef
whiteSpace :: Parser ()
whiteSpace = T.whiteSpace lexer
lexeme = T.lexeme lexer
mainParser = do whiteSpace
ds <- many ( digit <* whiteSpace )
eof
return ds
并在运行此代码后
*Main> parse mainParser "" " 31312 "
Right "31312"
*Main> parse mainParser "" " 3131 2 "
Right "31312"
*Main> parse mainParser "" " 313 1 2 "
Right "31312"
*Main> parse mainParser "" " 3 1 3 1 2 "
Right "31312"
*Main> parse mainParser "" " 31 3 1 2 "
Right "31312"
现在看起来很好。让我们试着看看这段代码如何处理空间。所有初始空格都由whiteSpace获取,剩余的输入传递给下一个函数(很多(数字&lt; * whiteSpace))。这里数字消耗一个数字,而whiteSpace消耗零或更多空间,这个计算的结果是数字的结果。查看lexeme的文档, lexeme p 首先应用解析器p而不是whiteSpace解析器,因此 lexeme digit 将首先消耗一个数字,然后消耗零个或多个空格。