Reputation: 998
Suppose I have this data type:
data Zinf = NegInf | Z Integer | PosInf deriving (Eq, Ord, Show)
It is also Num
, since all necessary operations are defined. When I type for example PosInf + 1
, the interpret returns PosInf
.
Now I derive yet another data type:
data Interval = Simple Integer | Complicated Zinf Zinf deriving (Eq, Show)
Now, since Zinf is also Num
, I can write down the following:
(Z 3) + 4
and I get
(Z 7)
I can also test
(Z 3) + 6 == 9
and the interpret returns True
.
I can also write Complicated 3 (6*7)
to get Complicated (Z 3) (Z 42)
.
Finally, I create a tree with these "Interval" data types:
data BinTree a = Empty | Node a (BinTree a) (BinTree a) deriving (Eq, Show)
type ITree = BinTree Interval
Now, when I try to write this function:
moveBy :: ITree -> Integer -> ITree
moveBy Empty _ = Empty
moveBy (Node (Simple a) l r) i = (Node (Simple (a+i)) (moveBy l i) (moveBy r i))
moveBy (Node (Complicated a b) l r) i = (Node ( Complicated (a + i) (b + i) ) (moveBy l i) (moveBy r i))
it produces the following error:
* Couldn't match expected type `Zinf' with actual type `Integer'
* In the second argument of `(+)', namely `i'
In the second argument of `Complicated', namely `(b + i)'
In the first argument of `Node', namely `(Complicated (a + i) (b + i))'
How come? b
should be of type Zinf
, b+i
again of type Zinf
, since i
is Integer
. And Complicated
expects exactly this kind of argument.
Upvotes: 1
Views: 73
Reputation: 153102
When you write
Z 3 + 4
it does not mean
Z 3 + (4 :: Integer)
but
Z 3 + (4 :: Zinf)
and uses fromInteger :: Integer -> Zinf
(implemented by you in your Num
instance) to interpret the 4
as a Zinf
. Indeed, addition must always be between two values of the same type -- say, two Zinf
s, or two Integer
s -- never between a Zinf
and an Integer
.
You may modify your moveBy
to take a Zinf
argument, so that addition is fine:
moveBy :: ITree -> Zinf -> ITree
-- implementation as in the question
Or you may convert the Integer
given to moveBy
to a Zinf
in the same way as is being implicitly done when you write Z 3 + 4
:
moveBy :: -- as in the question
moveBy (Node (Simple a) l r) i = Node (Simple (a+fromInteger i)) (moveBy l i) (moveBy r i)
-- and similarly for the Complicated case
Upvotes: 4
Reputation: 120731
Now, since Zinf is also Num, I can write down the following:
(Z 3) + 4
Yes, but it's important that (+)
has in this case not the type Zinf -> Integer -> Zinf
, as it may seem. You may be thinking 4
has type integer there, but it doesn't: it actually has type Zinf
. This is surprising since 3
does have type integer!
What's going on: Haskell number literals are polymorphic.
Prelude> :t 1
1 :: Num p => p
So, a number literal can have type Integer
or Float
or indeed Zinf
, depending on what the context demands. In (Z 3) + 4
this is Zinf
for 4
, so 4
has type Zinf
there. Great!
However, this does not work in Simple (a+i)
, because there the type of i
is fixed by the signature / context to be Integer
. Therefore you can't add it to a Zinf
.
What you can do however: any Integer
value can be “upgraded” into a polymorphic number (like number literals) by wrapping it† in fromInteger
. So, what you want there is
moveBy (...) i = (Node (Simple (a + fromInteger i)) (...) (...)
or equivalently Simple (a + Z i)
.
†Actually what's going on with number literals is that they also just wrap the “plain” integer literal in fromInteger
, to make it polymorphic.
Upvotes: 8