23

Take the type signature of fmap (the Functor method) as an example:

(a -> b) -> f a -> f b

How is that different from the following type signature?

a -> b -> f a -> f b

Is there even a difference between those two type signatures?

jub0bs
  • 60,866
  • 25
  • 183
  • 186
Trident D'Gao
  • 18,973
  • 19
  • 95
  • 159
  • 2
    How are the question in the text and the question in the title related? Parentheses in type signatures do *not* denote special semantics, they are for precedence, just like everywhere else in Haskell, which is why the two snippets are *not* equivalent. – Jörg W Mittag Dec 08 '15 at 00:58
  • 2
    @JörgWMittag: I agree that the two questions are not *equivalent* -- and in fact have different answers -- but I'm surprised that you find them *unrelated*. They're both about the meaning of parentheses in type signatures; a "yes" answer to the question in the title would probably entail a "yes" answer to the question in the text; and a good answer to either question would probably implicitly (or even explicitly) answer the other. – ruakh Dec 08 '15 at 09:04
  • 2
    Parentheses in type signatures denote precedence, just like in terms. Precedence is purely a *syntactic* property, it has no semantic significance. So, parentheses in type signatures are neither special nor semantics, and *that* is why the two snippets are not equivalent, just like `a + b * c` and `(a + b) * c` are not equivalent, also because of syntactic precedence and not because of semantics. – Jörg W Mittag Dec 08 '15 at 09:07

3 Answers3

33

Yes, there is a difference, because the -> type constructor is right-associative. In other words,

a -> b -> f a -> f b

is equivalent to

a -> (b -> (f a -> f b))

This type signature denotes a function that takes a parameter of type a and returns a function, which itself takes a parameter of type b and returns a function, which itself takes a parameter of type f a and returns a value of type f b.

On the other hand,

(a -> b) -> f a -> f b

denotes a function that takes a parameter of type a -> b (i.e. a function that takes a parameter of type a and returns a value of type b) and returns a function, which itself takes a parameter of type f a and returns a value of type f b.

Here is a contrived example that illustrates the difference between the two type signatures:

f :: (Int -> Bool) -> [Int] -> [Bool]
f = map

g :: Int -> Bool -> [Int] -> [Bool]
g n b = map (\n' -> (n' == n) == b)

λ> let ns = [42, 13, 42, 17]

λ> f (== 42) ns
[True,False,True,False]

λ> g 42 True ns
[True,False,True,False]

λ> g 42 False ns
[False,True,False,True]
jub0bs
  • 60,866
  • 25
  • 183
  • 186
13

Yes,

(a -> b) -> ...

means "given a function which takes a to b ...". While, this

a -> b -> ...

means "given some a and some b..."

Hamish
  • 1,015
  • 9
  • 20
6

Yes, the (a -> b) means one argument which is a function with signature a -> b, whereas a -> b -> ... means two arguments.

nbro
  • 15,395
  • 32
  • 113
  • 196
janneb
  • 36,249
  • 2
  • 81
  • 97