2011-08-27 52 views
1

我正在撰写自己的计划,并在this page上练习4。将readHex添加到Parsec分析器

我该如何解决这个问题?我有这么远,但不知道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

我已经得到了这么多,但不知道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 

当然,你可以省略类型签名,我只是说看看是否清晰。

此外,我不认为你可以在解析器LispVal函数上应用< |>对吗?

<|>适用于每Parser a

我推荐阅读解析器组合器上的一些材料,即Parsec User Guide

+0

由于'readHex :: Num a => String - > [(a,String)]'的类型,它并不是非常简单。看[这个问题](http:// stackoverflow。com/questions/7181390/pattern-matching-against-monadic-result)如何处理这个问题。 – hammar

+0

啊,我不知道readHex的类型签名。 – bzn

+0

谢谢!现在更接近理解!如果没有其他问题,请立即接受您的答案 – overscore

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 

结合分析器或获得花哨调整和内联和秒差距的许多工具。但我会从基础开始。

+0

感谢您的回复。 hexDigit位很有趣。 – overscore

+1

关于最后的代码片段 - 不要忘记Parsec的第一条规则 - “尽量避免尝试”。 –