将readHex添加到Parsec解析器

时间:2011-08-27 16:55:18

标签: haskell parsec

我正在为自己编写一个计划,并对this page的练习4感到震惊。

我该如何解决这个问题?我已经走到了这一步,但不知道readHex应该去哪里,我必须liftM吗?你的案例与解析器匹配吗?

parseNumber = liftM (Number . read) $ choice [many1 digit, char '#' >> oneOf "hd" >>= a]
    where a f = case f of
        'h' -> many1 digit

另外,我不认为你可以在<|>函数上应用Parser LispVal,对吗?

2 个答案:

答案 0 :(得分:2)

  

我已经走到了这一步,但不知道readHex应该去哪里,我必须解除它吗?

是的,因为readHex很可能是纯函数,liftM将其提升到Parser的monadic上下文中。

由于我不太了解您的本地函数a有什么用处,我暂时离开它并只使用函数parseDecimalparseHex。在这种情况下,您可以这样写parseNumber

parseNumber :: Parser LispVal
parseNumber = liftM Number $ parseDecimal <|> parseHex
    where parseDecimal :: Parser Integer
          parseDecimal = liftM read $ many1 digit
          parseHex :: Parser Integer
          parseHex     = liftM readHex $ char '#' >> ... -- parse hex value

当然你可以省略类型签名,为了清楚起见,我只是添加了它们。

  

此外,我不认为你可以申请&lt; |&gt;在Parser LispVal函数上,对吧?

<|>适用于每个Parser a

我建议在解析器组合器上阅读一些材料,即Parsec User Guide

答案 1 :(得分:1)

我稍微改变了布局,但这是我们正在考虑的代码示例:

parseNumber = 
    liftM (Number . read) $ 
        choice [many1 digit, char '#' >> oneOf "hd" >>= a]
    where
    a f =
        case f of
            'h' -> many1 digit

我认为你在知道事情应该如何结合之前,试图同时做太多事情。您不得不将readHex移动到(Number . read)部分而不是read,具体取决于正在读取的数字类型。

这是一个十六进制数的解析器,它不使用liftM或其他奇特的组合器:

parseHex :: Parser LispVal
parseHex = do
    char '#'
    char 'x'
    digits <- many1 hexDigit   -- hexDigit is defined by Parsec.
    return (Number (fst (readHex digits !! 0)))

这里棘手的部分是提取readHex的结果。

您可以将解析器与

组合使用
try parseHex <|> try parseOct <|> ... <|> parseDec

或者喜欢Parsec的调优和内联以及许多工具。但我从基础开始。