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的第一條規則 - 「儘量避免嘗試」。 –