我正在尝试使用parsec解析haskell中的输入整数字符串。字符串可以是十进制,八进制或十六进制。对于十进制,八进制和十六进制,基数由#d
,#o
或#x
的前缀指定,然后是整数。如果没有指定前缀,则假定基数为10.这是我到目前为止所做的:
parseNumber = do x <- noPrefix <|> withPrefix
return x
where noPrefix = many1 digit
withPrefix = do char '#'
prefix <- oneOf "dox"
return $ case prefix of
'd' -> many1 digit
'o' -> fmap (show . fst . head . readOct) (many1 octDigit)
'x' -> fmap (show . fst . head . readHex) (many1 hexDigit)
但是,这不是编译,并且因类型错误而失败。我不太了解类型错误,并且只想帮助解决这个问题。任何其他解决方法也将受到赞赏。
感谢您的时间和帮助。 :)
编辑:Here's我遇到的错误。
答案 0 :(得分:1)
您有两个小错误:
一个缩进错误(return x
必须缩进,与do
相比)并且withPrefix中的解析器不能return
,因为他们无论如何都会return
他们的结果。
parseNumber = do x <- noPrefix <|> withPrefix
return x
where noPrefix = many1 digit
withPrefix = do char '#'
prefix <- oneOf "dox"
case prefix of
'd' -> many1 digit
'o' -> fmap (show . fst . head . readOct) (many1 octDigit)
'x' -> fmap (show . fst . head . readHex) (many1 hexDigit)
这应该有效
答案 1 :(得分:1)
在Megaparsec - 一个现代的
Parsec的fork,这个问题是不存在的(来自
documentation of hexadecimal
):
以十六进制表示形式解析整数。代表 根据Haskell报告,预计十六进制数除外 因为这个解析器没有解析“0x”或“0X”前缀。它是 程序员在解析之前解析正确的前缀的责任 数字本身。
例如,您可以使其符合Haskell报告,如下所示:
hexadecimal = char '0' >> char' 'x' >> L.hexadecimal
因此,在您的情况下,您可以定义(注意它的可读性如何):
import Data.Void
import Text.Megaparsec
import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L
type Parser = Parsec Void String
parseNumber :: Parser Integer
parseNumber = choice
[ L.decimal
, (string "o#" *> L.octal) <?> "octal integer"
, (string "d#" *> L.decimal) <?> "decimal integer"
, (string "h#" *> L.hexadecimal) <?> "hexadecimal integer" ]
让我们尝试解析器(注意错误消息的质量):
λ> parseTest' (parseNumber <* eof) ""
1:1:
|
1 | <empty line>
| ^
unexpected end of input
expecting decimal integer, hexadecimal integer, integer, or octal integer
λ> parseTest' (parseNumber <* eof) "d#3"
3
λ> parseTest' (parseNumber <* eof) "h#ff"
255
λ> parseTest' (parseNumber <* eof) "o#8"
1:3:
|
1 | o#8
| ^
unexpected '8'
expecting octal integer
λ> parseTest' (parseNumber <* eof) "o#77"
63
λ> parseTest' (parseNumber <* eof) "190"
190
完全披露:我是Megaparsec的作者/维护者。