3

我正在编写自己的计划,并对本页上的练习 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

4

2 回答 2

3

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

是的,因为readHex很可能是一个纯函数并将liftM其提升到Parser.

由于我不太了解您的本地函数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

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

另外,我不认为您可以将 <|> 应用于 Parser LispVal 函数,对吗?

<|>适用于每个Parser a.

我建议阅读一些关于解析器组合器的材料,即Parsec 用户指南

于 2011-08-27T19:29:33.123 回答
1

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

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

我认为你在知道事情应该如何结合之前试图同时做太多事情。您必须以某种方式将 areadHex移入该(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 的许多工具。但我会从基础开始。

于 2011-08-27T20:22:33.097 回答