Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: pattern matching on Num types

Why can't Haskell perform pattern matching on Num types, without us specifying Eq as a type class?

For instance:

h :: Num a => a -> a
h 0 = -1
h x = x + 1

When compiling this function, ghci complains:

    * Could not deduce (Eq a) arising from the literal `0'
      from the context: Num a
        bound by the type signature for:
                   h :: forall a. Num a => a -> a
        at functions.hs:9:1-20
      Possible fix:
        add (Eq a) to the context of
          the type signature for:
            h :: forall a. Num a => a -> a
    * In the pattern: 0
      In an equation for `h': h 0 = - 1
   |
10 | h 0 = -1
   |   ^

Changing the function definition as following compiles and runs perfectly:

h :: (Num a, Eq a) => a -> a
h 0 = -1
h x = x + 1

*Main> h 0
-1
*Main>
like image 232
Guillaume Avatar asked Feb 11 '18 05:02

Guillaume


1 Answers

From the Haskell 2010 Report, the section entitled Informal Semantics of Pattern Matching:

Matching a numeric, character, or string literal pattern k against a value v succeeds if v == k

So when you use a literal (such as 0) as a pattern, its meaning depends upon == (a method of the Eq class).

For example, your function h

h 0 = -1
h x = x + 1

can be rewritten as

h x | x == 0 = -1
h x          = x + 1

You are (implicitly) using the == method, therefore you need an Eq constraint.

There are two important observations here about how Haskell differs from a lot of other languages:

  1. The notion of equality is not defined for all types. One cannot ask whether x == y unless the type of x and y has an Eq instance.
  2. The set of numeric types is not fixed. A numeric literal can take on any type that has an instance of Num. You can define your own type and make it an instance of Num, and it doesn't necessarily have to also have an instance of Eq. So not all "numbers" can be compared for equality.

So it is insufficient for the context of your function h to be "a has to be a number." The context must be, more specifically, "a has to be a number with an equality test" to ensure that there is a way to check whether x is equal to 0 in order to perform the pattern match.

like image 173
Chris Martin Avatar answered Oct 03 '22 20:10

Chris Martin