In Learn you a Haskell, it is given the following example:
map ($ 3) [(4+), (10*), (^2), sqrt]
[7.0,30.0,9.0,1.7320508075688772]
However, I don't understand why this works.
The signatures of the functions are
Prelude> :info ($)
($) :: (a -> b) -> a -> b
Prelude> :t ($ 3)
($ 3) :: Num a => (a -> b) -> b
However, ->
is a left-associative operator, so $ :: (a -> b) -> a -> b
is actually ((($ :: (a-b))-> a)-> b)
, so shouldn't 3
in ($ 3)
correspond to (a->b)
function that is the first "variable" of the function $
? i.e why is ($ 3)
a function of signature (a -> b) -> b
However,
->
is a left-associative operator.
No, ->
is a right-associative operator. In the Learn You a Haskell documentation, it says:
First of all, notice the type declaration. Before, we didn't need parentheses because
->
is naturally right-associative.
A more verbose version of the type signatures of ($)
and ($ 3)
are:
($) :: (a -> b) -> (a -> b)
($ 3) :: Num a => (a -> b) -> b
we can write the type constructors in a more canonical form as:
($) :: (->) ((->) a b) ((->) a b)
($ 3) :: Num a => (->) ((->) a b) b
This thus means that $
takes a function with signature a -> b
, and thus returns a function with signature a -> b
, it thus basically acts as id
, except that it constrants the input to a function (and not just any type), and that you can use $
easily whereas (`id` 3)
is not that elegant.
If we thus apply 3
to the f $ 3
operator, we know that f
will have signature f :: a -> b
, and 3
will have type Num a => a
. If we work with operator sectioning with ($ 3)
, we pass 3
as the "second" parameter (in Haskell every function has exactly one parameter, but here we assign it thus to the parameter that is the result of ($) f
, this thus means that the type of ($ 3)
is Num a => (a -> b) -> b
.