I got a problem with the implementation of the readsPrec to parse an input for following datastructure:
data Term = Monom Int Int
| Addition Term Term
| Subtraction Term Term
| Multiplication Term Term
| Division Term Term
I already implemented an instance of show which makes a monom look like:
let k = Monom 2 3
Main.show k
returns:
(2x^3)
and
let m = Addition k k
Main.show m
returns:
(2x^3)+(2x^3)
Meanwhile I'm sitting like 5 hours around with the task and I really haven't any clue how to deal with it. My first approach looked like this:
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), "")]
At first I felt very happy until I noticed that this code doesn't work for anything else than Monom. Anyone got an better approach?
Yes. This might seem a little overpowered, but using a parser combinator library like Parsec would allow you to write the code neatly. E.g.
As an explanation,
monom
parses something like2x^3
(without brackets),operations
takes a list of tuples and parses aterm
followed by one of the operation characters, followed by anotherterm
, and then uses the appropriate data constructor to make the right instance (thefromJust $ lookup c ops
line).The
term
parser parses either amonom
or one of the operations, surrounded by brackets.term'
parses a whole string (i.e. makes sure that the parser runs to the end of the string).readTerm
is just a "cleaner" version of the parser.Some examples:
The above is a very basic version, and can easily be extended to (for example) make the
coef
term optional, so thatx^2
parses asMonom 1 2
, or make thepower
term optional so that2x
parses asMonom 2 1
. (Theoption
function is extremely useful for this specific modification, and only adds 1 or 2 more lines.)(Note. this might be more efficient and elegant written in an applicative style, e.g.
but this can get a bit unweildy when making modifications.)