Haskell读取了理性函数

时间:2012-10-22 08:04:56

标签: haskell input instance rational-number

我遇到了READPrec的实现问题,无法解析以下数据结构的输入:

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

我已经实现了一个show的实例,它使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 个答案:

答案 0 :(得分:2)

是。这可能看起来有点过于强大,但使用像Parsec这样的解析器组合库可以让你整齐地编写代码。 E.g。

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,或者使{ {1}}术语可选,以便power解析为2x。 (option函数对于此特定修改非常有用,并且只增加1或2行。)

(注意:这可能是更有效和优雅的应用风格,例如

Monom 2 1

但是在进行修改时这可能会有点不合适。)