2012-10-22 122 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