如何使用haskell中的parsec解析带有基本前缀的整数?

时间:2015-12-16 14:41:31

标签: parsing haskell parsec

我正在尝试使用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我遇到的错误。

2 个答案:

答案 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的作者/维护者。