Perhaps the best thing to do is to think about two simpler functions:
f :: a -> (b -> c)
g :: (a -> b) -> c
Let's look at these functions in turn.
The first function, f
, takes a single parameter of type a
, and returns a function of type b -> c
. In other words, you could write something like the following, assuming x :: a
, y :: b
, and z :: c
:
f :: a -> (b -> c)
f x = f'
where f' :: b -> C
f' y = z
Another way to write the signature of f
is as:
f :: a -> b -> c
This works because by default we bind ->
to the right. It also gives us another equivalent way of understanding f
: it can be thought of a function that takes two parameters, of type a
and b
, and produces a result of type c
.
The second function, g
takes one argument, which is a function of type a -> b
.
g :: (a -> b) -> c
g h = z
where h :: a -> b
Thus the two are very different.
Applying this to your functions, the first function takes 4 values of type Int
and returns an Int
. The second function takes a single function of type ((Int -> Int) -> Int) -> Int
, and that's a function that takes a third function of type (Int -> Int)
and produces an Int
, and so on.