This is the code I have which results in the error that follows:
import Prelude hiding (div)
data Expr = Expr Op Int Int deriving (Show)
data Op = Add | Sub | Mul | Div deriving (Show)
evaluate :: (Num a) => Expr -> a
evaluate (Expr Add a b) = a + b
--evaluate (Expr Sub a b) = sub a b
--evaluate (Expr Mul a b) = mul a b
--evaluate (Expr Div a b) = div a b
Error message:
exprs.hs:8:27: error:
• Couldn't match expected type ‘a’ with actual type ‘Int’
‘a’ is a rigid type variable bound by
the type signature for:
evaluate :: forall a. Num a => Expr -> a
at exprs.hs:7:1-32
• In the expression: a + b
In an equation for ‘evaluate’: evaluate (Expr Add a b) = a + b
• Relevant bindings include
evaluate :: Expr -> a (bound at exprs.hs:8:1)
|
8 | evaluate (Expr Add a b) = a + b
| ^^^^^
Failed, 0 modules loaded.
However, the (+) function has type (Num a) => a -> a -> a
, and
the pattern I'm matching in the function evaluate
has two Ints (a & b) which are both part of the Num typeclass. Since the result of calling (+) on a & b will be of type Int (from the Num typeclass) and that is also what I'm declaring the type of the output of my evaluate
function to be, why is GHCi giving me this error?
Note that, if I change the type declaration of evaluate
to
evaluate :: Expr -> Int
then this error does not come up.
evaluate :: (Num a) => Expr -> a
states that for any type a
which has a Num
instance, evaluate
can return a value of type a
given an Expr
value. However given the definition of Expr
, you can only ever return an Int
, and the compiler is therefore rejecting your definition.
If it were allowed you would be able to do:
evaluate (Expr Add 2 3) :: Double
which your definition cannot satisfy.
You can use your definition if you allow Expr
to be parameterised by the expression type:
data Expr a = Expr Op a a deriving (Show)
evaluate :: (Num a) => Expr a -> a
evaluate (Expr Add a b) = a + b
...