如何在 haskell 中使用 parsec 解析带有基本前缀的整数?
How to parse integer with base prefix using parsec in haskell?
我正在尝试使用 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 我遇到的错误。
你有两个小错误:
一个缩进错误(return x
与 do
相比必须缩进)并且 withPrefix 中的解析器不能 return
ed,因为它们将 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)
这应该有效
在Megaparsec——现代
Parsec 的分支,这个问题是 non-existent(来自
documentation of hexadecimal
):
Parse an integer in hexadecimal representation. Representation of
hexadecimal number is expected to be according to Haskell report except
for the fact that this parser doesn't parse “0x” or “0X” prefix. It is
responsibility of the programmer to parse correct prefix before parsing
the number itself.
For example you can make it conform to Haskell report like this:
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
Full-disclosure:我是百万秒差距的author/maintainer。
我正在尝试使用 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 我遇到的错误。
你有两个小错误:
一个缩进错误(return x
与 do
相比必须缩进)并且 withPrefix 中的解析器不能 return
ed,因为它们将 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)
这应该有效
在Megaparsec——现代
Parsec 的分支,这个问题是 non-existent(来自
documentation of hexadecimal
):
Parse an integer in hexadecimal representation. Representation of hexadecimal number is expected to be according to Haskell report except for the fact that this parser doesn't parse “0x” or “0X” prefix. It is responsibility of the programmer to parse correct prefix before parsing the number itself.
For example you can make it conform to Haskell report like this:
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
Full-disclosure:我是百万秒差距的author/maintainer。