I'm going through a haskell tutorial (Learn you a haskell for great good) and I was playing around with this code I wrote based of off one of the functions in the book.
reverseNum :: (Num a) => a -> a
reverseNum 123 = 321
reverseNum x = 0
and ghci tells me that it can't deduce (Eq a) from (Num a).
So I change the first line to this
reverseNum :: (Integral a) => a -> a
and it worked. This was strange because I thought to be a part of the Num typeclass you needed to also be apart of Eq.
I tried one more thing to satisfy me curiosity and changed the first 2 lines to this
reverseNum :: (Floating a) => a -> a
reverseNum 1.0 = 0.1
and it gave me the same error.
I know that you can fix this by doing something like reverseNum :: (Num a, Eq a) ...
but I want to know why Integral is the only one where Eq can be deduced.
Why is that?
P.S. I am really new to haskell so... be gentle :)
Because that's the definition of Num
in the prelude:
class Num a where
...
Whereas the definition for Integral
requires the type to be Real
and Enum
:
class (Real a, Enum a) => Integral a where
...
And Real
implies both Num
and Ord
...
class (Num a, Ord a) => Real a where
...
And Ord
, naturally, implies Eq
:
class Eq a => Ord a where
...
This line means that in order to make something implement Ord
, it must also implement Eq
. Or we could say that Ord
is a subclass of Eq
. Anyway...
The summary is that Num
is not a subclass of Eq
, but Integral
is a subclass of Eq
.
You can imagine implementing Num
in ways that make it impossible to implement Eq
.
newtype Sequence = Sequence (Integer -> Integer)
instance Num Sequence where
(Sequence x) + (Sequence y) = Sequence $ \pt -> x pt + y pt
(Sequence x) - (Sequence y) = Sequence $ \pt -> x pt - y pt
(Sequence x) * (Sequence y) = Sequence $ \pt -> x pt * y pt
negate (Sequence x) = Sequence $ \pt -> -pt
abs (Sequence x) = Sequence $ \pt -> abs pt
signum (Sequence x) = Sequence $ \pt -> signum pt
fromInteger = Sequence . const
-- Ignore the fact that you'd implement these methods using Applicative.
Here, Sequence
is the type representing all computable sequences. You can't implement Eq
in any reasonable way, because the sequences are infinitely long!
instance Eq Sequence where
-- This will never return True, ever.
(Sequence x) == (Sequence y) =
and [x pt == y pt | pt <- [0..]] &&
and [x pt == y pt | pt <- [-1,-2..]]
So it makes sense that Num
is not a subclass of Eq
, because there are useful types which can implement Num
but not Eq
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With