I know
$ :: (a->b) -> a -> b
f $ x = f x
Intuitively it seems to me, like to say, 1. $ delays the evaluation of the function to its left 2. evaluates whats to its right 3. feeds the result of its left to its right.
And it makes perfect sense to me when,
ghci> length $ [1..5]
5
ghci> ($) length [1..5]
5
What I do not understand is why,
ghci> ($ [1..5]) length
5
Judging from the type of $, isn't that its (first) argument should be a function ?
This has to do with parsing. In Haskell you can write (op arg)
where op
is an infix operator. This is not the same as ((op) arg)
. And you can write (arg op)
as well! For example:
GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help
Prelude> :t (+ 4)
(+ 4) :: Num a => a -> a
Prelude> :t (4 +)
(4 +) :: Num a => a -> a
That is, (+ 4)
is the function \x -> x + 4
and (4 +)
is the function \y -> 4 + y
. In the case of addition these are equal functions, but that is not really important right now.
Now let us try the same trick on $
:
Prelude> :t ($ [1,2,3,4])
($ [1,2,3,4]) :: Num t => ([t] -> b) -> b
Now surprise so far, we got \f -> f $ [1,2,3,4]
. We can also write
Prelude> :t (length $)
(length $) :: [a] -> Int
to get the function \l -> length $ l
. But how about this:
Prelude> :t ($ length)
($ length) :: (([a] -> Int) -> b) -> b
This is strange, but it makes sense! We got \f -> f $ length
, i.e., a functional which expects to get a function f
of type ([a] -> Int) -> b)
that will be applied to length
. There is a fourth possibility:
Prelude> :t ([1,2,3,4] $)
<interactive>:1:2:
Couldn't match expected type `a0 -> b0' with actual type `[t0]'
In the first argument of `($)', namely `[1, 2, 3, 4]'
In the expression: ([1, 2, 3, 4] $)
Everything is as it should be because [1,2,3,4]
is not a function. What if we write $
in parenthesis? Then its special meaning as an infix operator disappears:
Prelude> :t (($) length)
(($) length) :: [a] -> Int
Prelude> :t (($) [1,2,3,4])
<interactive>:1:6:
Couldn't match expected type `a0 -> b0' with actual type `[t0]'
In the first argument of `($)', namely `[1, 2, 3, 4]'
In the expression: (($) [1, 2, 3, 4])
Prelude> :t (length ($))
<interactive>:1:9:
Couldn't match expected type `[a0]'
with actual type `(a1 -> b0) -> a1 -> b0'
In the first argument of `length', namely `($)'
In the expression: (length ($))
Prelude> :t ([1,2,3,4] ($))
<interactive>:1:2:
The function `[1, 2, 3, 4]' is applied to one argument,
but its type `[t0]' has none
In the expression: ([1, 2, 3, 4] ($))
So, to answer your question: $ [1,2,3,4]
is parsed as \f -> f $ [1,2,3,4]
so it makes perfect sense to apply it to length
. However ($) [1, 2, 3, 4]
does not make much sense because ($)
is not seen as an infix operator.
By the way, $
does "not do anything", so to speak. It is mostly used for more readable input because it has low precedence and so we can write f $ g $ h $ x
instead of f (g (h x))
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With