emi
emi

Reputation: 5410

Error: "No instances for (x)..."

Exercise 14.16-17 in Thompson asks me to add the operations of multiplication and (integer) division to the type Expr, which represents a simple language for arithmetic, then define the functions show and eval (evaluates an expression of type Expr) for Expr.

My solution works for each arithmetic operation except division:

data Expr = L Int
          | Expr :+ Expr
          | Expr :- Expr
          | Expr :* Expr
          | Expr :/ Expr

instance Num Expr where
 (L x) + (L y) = L (x + y)
 (L x) - (L y) = L (x - y)
 (L x) * (L y) = L (x * y)

instance Eq Expr where
 (L x) == (L y) = x == y

instance Show Expr where
 show (L n) = show n
 show (e1 :+ e2) = "(" ++ show e1 ++ " + " ++ show e2 ++ ")"
 show (e1 :- e2) = "(" ++ show e1 ++ " - " ++ show e2 ++ ")"
 show (e1 :* e2) = "(" ++ show e1 ++ " * " ++ show e2 ++ ")"
 show (e1 :/ e2) = "(" ++ show e1 ++ " / " ++ show e2 ++ ")"

eval :: Expr -> Expr
eval (L n) = L n
eval (e1 :+ e2) = eval e1 + eval e2
eval (e1 :- e2) = eval e1 - eval e2
eval (e1 :* e2) = eval e1 * eval e2

E.g.,

*Main> (L 6 :+ L 7) :- L 4
  ((6 + 7) - 4)
*Main> it :* L 9
  (((6 + 7) - 4) * 9)
*Main> eval it
  81
  it :: Expr

However, I am running into problems when I try to implement division. I don't understand the error message I receive when I try to compile the following:

instance Integral Expr where
 (L x) `div` (L y) = L (x `div` y)

eval (e1 :/ e2) = eval e1 `div` eval e2

This is the error:

Chapter 14.15-27.hs:19:9:

No instances for (Enum Expr, Real Expr)
  arising from the superclasses of an instance declaration
               at Chapter 14.15-27.hs:19:9-21
Possible fix:
  add an instance declaration for (Enum Expr, Real Expr)
In the instance declaration for `Integral Expr'

In the first place, I have no idea why defining div for the data type Expr requires me to define an instance of Enum Expr or Real Expr.

Upvotes: 1

Views: 589

Answers (1)

Dario
Dario

Reputation: 49218

Well, that's the way the Integral typeclass is defined. For information, you can e.g. just type :i Integral into GHCi.

You'll get

class (Real a, Enum a) => Integral a where ...

which means any type a that should be Integral has to be Real and Enum first. C'est la vie.


Note that maybe you've got your types messed up quite a bit. Take a look at

instance Num Expr where
 (L x) + (L y) = L (x + y)
 (L x) - (L y) = L (x - y)
 (L x) * (L y) = L (x * y)

This just allows you to add Expressions if they wrap plain numbers. I'm pretty sure you don't want that. You want to add arbitrary expressions and you already have a syntax for this. It's just

instance Num Expr where
  (+) = (:+)
  (-) = (:-)
  -- ...

This allows you to write (L 1) + (L 2) with perfectly normal syntax. Likewise, eval should not just reduce expressions but yield a number, and therefore have the type eval :: Expr -> Integer. Division is simple for that matter

eval (a :/ b) = (eval a) `div` (eval b)

which is defined since you just divide numbers.

Upvotes: 3

Related Questions