2012-10-22 38 views
2

我與readsPrec的實施問題解析爲以下數據結構的輸入:哈斯克爾readsPrec有理函數

data Term = Monom Int Int 
         | Addition Term Term 
         | Subtraction Term Term 
         | Multiplication Term Term 
         | Division Term Term 

我已經實現了節目的一個實例,它使得monom樣子:

let k = Monom 2 3 
Main.show k 

回報:

(2x^3) 

let m = Addition k k 
Main.show m 

回報:

(2x^3)+(2x^3) 

同時我圍坐像5小時的任務,我真的沒有任何線索如何處理它。我的第一種方法是這樣的:

instance Read Term where 
 readsPrec _ inp = let[(a,b)] = lex inp in 
  case a of 
  "x" -> readsPrec 0 b 
  "^" -> [(Monom 1 (read b::Int), "")] 
  c  -> let[(d, "")] = readsPrec 0 b in 
    [(Monom (read c::Int) ((\(Monom x y) -> y) d), "")] 

起初,我覺得很開心,直到我發現這個代碼不爲別的比Monom工作。任何人都有更好的方法?

+1

我建議你看看[這個答案](http://stackoverflow.com/a/6794085/1147955),並考慮只是'deriving'閱讀和顯示爲您的數據類型。當然,你仍然可能想用比'Addition(Monom 1 3)(Monom 2 3)''更方便的格式解析輸入(並顯示輸出)'。是這樣嗎?如果是這樣,你可以使用一些解析器生成器或解析庫,如Parsec。但它不是100%清楚你想要做什麼。 –

回答

2

是的。這可能看起來有點過度,但使用像Parsec這樣的解析器組合器庫將允許您整齊地編寫代碼。例如。

import Text.ParserCombinators.Parsec 
import Data.Maybe 

monom, term :: Parser Term 
operations :: [(Char,(Term -> Term -> Term))] -> Parser Term 

int :: Parser Int 
int = fmap read $ many1 digit 

monom = do 
     coef <- int 
     string "x^" 
     power <- int 
     return $ Monom coef power 


operations ops = do 
        a <- term 
        c <- choice . map (char . fst) $ ops 
        b <- term 
        return $ (fromJust $ lookup c ops) a b 

term = do 
     char '(' 
     x <- monom <|> (operations [('+', Addition), ('-', Subtraction), ('*', Multiplication), ('/', Division)]) 
     char ')' 
     return x 

term' = do 
     x <- term 
     eof 
     return x 

readTerm :: String -> Term 
readTerm string = case parse term' "" string of 
         Left err -> error . show $ err 
         Right term -> term 

作爲解釋,monom解析像2x^3(不帶括號),operations取元組的列表,並解析term隨後通過操作字符之一,然後另一term,然後使用適當的數據構造函數做出正確的實例(fromJust $ lookup c ops一行)。

解析器term解析monom或括號括起來的其中一個操作。 term'解析整個字符串(即確保解析器運行到字符串的末尾)。 readTerm只是解析器的「更清潔」版本。

一些例子:

> readTerm "(2x^3)" 
Monom 2 3 
> readTerm "((2x^3)+(2x^3))" 
Addition (Monom 2 3) (Monom 2 3) 
> readTerm "(((2x^3)+(2x^3))*(2x^3))" 
Multiplication (Addition (Monom 2 3) (Monom 2 3)) (Monom 2 3) 

上面是一個非常基本的版本,並且可以容易地擴展到(例如)使coef術語可選的,以便x^2解析作爲Monom 1 2,或使power術語可選,因此2x解析爲Monom 2 1。 (該option函數爲這個特定的修飾極爲有用的,並且只增加1條或2個更多的線。)

(注意,這可能是更有效和優雅寫在應用性的風格,例如

import Control.Applicative 

monom = Monom <$> int <* string "x^" <*> int 

但這可以得到一點unweildy進行修改時。)

+0

哇,謝謝!這個解決方案似乎工作得很好。不幸的是,它不符合我使用readsPrec實現解決方案的要求。您是否發現使用readsPrec實現此解決方案的可能性?我非常感謝你的幫助! – RodrigoDela

+1

爲什麼你想要它作爲'readsPrec'? – augustss

+0

我被要求以這種方式實施。有關係嗎?我也想提高我對課堂的理解閱讀本身... – RodrigoDela