0

I'm trying to understand manually specifying Haskell function signatures better, and I don't understand the => operator in this context.

Here's my example:

Prelude> add a b = a + b 
Prelude> add 1 2
3

Haskell has inferred this function signature:

Prelude> :info add
add :: Num a => a -> a -> a 

This looks great, because if I were to have defined this manually, I would have done:

add :: Int -> Int -> Int
add a b = a + b

So, I understand the inferred type is better, because it allows:

Prelude> add 1.0 2.0
3.0
Prelude> add 1.0 2
3.0

But how should I read what is happening with

Num a => a -> a -> a

?

Why would this not be written, for example, as:

add :: Num -> Num -> Num

or

add :: Num a -> Num a -> Num a

?

Both of these fail:

add :: Num -> Num -> Num


[1 of 1] Compiling Main             ( my.hs, interpreted )

my.hs:4:8: error:
    • Expecting one more argument to ‘Num’
      Expected a type, but ‘Num’ has kind ‘* -> Constraint’
    • In the type signature: add :: Num -> Num -> Num
  |
4 | add :: Num -> Num -> Num
  |        ^^^

my.hs:4:15: error:
    • Expecting one more argument to ‘Num’
      Expected a type, but ‘Num’ has kind ‘* -> Constraint’
    • In the type signature: add :: Num -> Num -> Num
  |
4 | add :: Num -> Num -> Num
  |               ^^^

my.hs:4:22: error:
    • Expecting one more argument to ‘Num’
      Expected a type, but ‘Num’ has kind ‘* -> Constraint’
    • In the type signature: add :: Num -> Num -> Num
  |
4 | add :: Num -> Num -> Num
  |                      ^^^
Failed, no modules loaded.

and

add :: Num a -> Num a -> Num a

my.hs:4:8: error:
    • Expected a type, but ‘Num a’ has kind ‘Constraint’
    • In the type signature: add :: Num a -> Num a -> Num a
  |
4 | add :: Num a -> Num a -> Num a
  |        ^^^^^

my.hs:4:17: error:
    • Expected a type, but ‘Num a’ has kind ‘Constraint’
    • In the type signature: add :: Num a -> Num a -> Num a
  |
4 | add :: Num a -> Num a -> Num a
  |                 ^^^^^

my.hs:4:26: error:
    • Expected a type, but ‘Num a’ has kind ‘Constraint’
    • In the type signature: add :: Num a -> Num a -> Num a
  |
4 | add :: Num a -> Num a -> Num a
  |                          ^^^^^
Failed, no modules loaded.

So I get that this is the correct syntax. But what is this operator "=>" called---that is, how would I read/pronounce the signature above in spoken English---and where can I look up its syntax in the function definition and elsewhere?

Mittenchops
  • 18,633
  • 33
  • 128
  • 246
  • 2
    `=>` describes context. I'd read it as "Given a numeric type `a`, the function takes an `a` and returns a function from `a` to `a`. – Amadan Dec 28 '18 at 08:07
  • 2
    A function `a -> a -> a` takes two arguments of the same arbitrary type and returns a value of such type. Is can be used on two strings, two ints, two floats, two booleans, etc. The caller chooses `a` freely. Adding the constraint `Num a =>` limits the choice of `a` to numeric types (and, dually, allows to use arithmetic operators `+,-,*` in the definition of the function). – chi Dec 28 '18 at 09:00
  • The error message says it all. `Num` isn't a type, nor is `Num a`. What you want to say is "this function takes any 2 arguments of the same type, and returns another of that type - but that type must be an instance of the `Num` typeclass". Which is exactly what the inferred type signature says. Granted you could probably choose slightly different syntax for this than what Haskell does, but it's not obvious how else to do it without making the declarations more verbose. – Robin Zigmond Dec 28 '18 at 11:12
  • @duplode, can my question stand as a no duplicate because I’m asking for pronunciation as well? I also like the concise answer given to this one. – Mittenchops Dec 28 '18 at 11:56
  • @Mittenchops On pronounciation, I don't feel there is a definitive answer. There are suggestions around about using "then" or "implies"; however, while those make sense in a way, I don't think people actually use them in the wild very much. Rather, it tends to come out as "[how one would otherwise read the signature], with `a` being an instance of `Num`", or something similarly prosaic (see also Robin Zigmond's comment just above). – duplode Dec 28 '18 at 14:21

1 Answers1

5

If we have type:

add :: Num a => a -> a -> a

=> is delimiter between constraint part and signature itself.

Num a mean that a must belong to Num typeclass.

You can have multiple constraints (Num a, Show a) => a or constraints for different types (Num a, Eq b) => a -> b -> c

talex
  • 17,973
  • 3
  • 29
  • 66