Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does equality work for numeric types?

I see that Haskell allows different numeric types to be compared:

*Main> :t 3
3 :: Num t => t
*Main> :t 3.0
3.0 :: Fractional t => t
*Main> 3 == 3.0
True

Where is the source code for the Eq instance for numeric types? If I create a new type, such as ComplexNumber, can I extend == to work for it? (I might want complex numbers with no imaginary parts to be potentially equal to real numbers.)

like image 339
Ellen Spertus Avatar asked May 02 '26 04:05

Ellen Spertus


1 Answers

“Haskell allows different numeric types to be compared” no it doesn't. What Haskell actually allows is different types to be defined by the same literals. In particular, you can do

Prelude> let a = 3.7 :: Double
Prelude> let b = 1   :: Double
Prelude> a + b
4.7

OTOH, if I declared these explicitly with conflicting types, the addition would fail:

Prelude> let a = 3.7 :: Double
Prelude> let b = 1   :: Int
Prelude> a + b

<interactive>:31:5:
    Couldn't match expected type ‘Double’ with actual type ‘Int’
    In the second argument of ‘(+)’, namely ‘b’
    In the expression: a + b

Now, Double is not the most general possible type for either a or b. In fact all number literals are polymorphic, but before any operation (like equality comparison) happens, such a polymorphic type needs to be pinned down to a concrete monomorphic one. Like,

Prelude> (3.0 :: Double) == (3 :: Double)
True

Because ==, contrary to your premise, actually requires both sides to have the same type, you can omit the signature on either side without changing anything:

Prelude> 3.0 == (3 :: Double)
True

In fact, even without any type annotation, GHCi will still treat both sides as Double. This is because of type defaulting – in this particular case, Fractional is the strongest constraint on the shared number type, and for Fractional, the default type is Double. OTOH, if both sides had been integral literals, then GHCi would have chosen Integer. This can sometimes make a difference, for instance

Prelude> 10000000000000000 == 10000000000000001
False

but

Prelude> 10000000000000000 ==(10000000000000001 :: Double)
True

because in the latter case, the final 1 is lost in the floating-point error.

like image 143
leftaroundabout Avatar answered May 05 '26 01:05

leftaroundabout