Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could not deduce (Eq a) from (Num a) or from (Floating a). But Can deduce (Eq a) from (Integral a). Why?

Tags:

haskell

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 :)

like image 908
benbot Avatar asked Sep 07 '13 18:09

benbot


1 Answers

Short answer

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.

Long answer (why?)

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.

like image 139
Dietrich Epp Avatar answered Oct 14 '22 01:10

Dietrich Epp