This question already has an answer here:
-
What does $ mean/do in Haskell?
2 answers
This happens in the situation you want to apply bunch of functions to the same variable, it may look like this:
map (\f->f 4) [odd, even]
but from LYAH using $
make it very neat
map ($ 4) [odd, even]
why does it work. first I type it in ghci like $ 4 odd
, it failed, then I type ($ 4) odd
, which works fine. then I check the type of ($ 4)
using :t
which shows ($ 4) :: Num a => (a -> b) -> b
, odd
is odd :: Integral a => a -> Bool
. It seems make sense, but still not clear to me.
Can anyone explain it clearly, is it another common usage of $
, and is there other more usage of $
.
Anatomy of the operator
The $
application operator is in the form:
($) :: (a -> b) -> a -> b
It's often seen in situation when you want to avoid a trailing pair of parenthesis:
func a (b + c)
is equal to:
func a $ b + c
The magic behind this is simply explained in its fixity declaration:
infixr 0
This means: everything that is after $
will be grouped into a single entity, just like if they where enclosed in parenthesis.
Of course this can be also "nested" like so:
func a $ b + other $ c - d
which means:
func a (b + other (c - d))
Application operator as function
Your case is very interesting and, in my experience, not used very often.
Let's analyze this:
map ($ 4) [odd, even]
We know that map
's type is:
map :: (a -> b) -> [a] -> [b]
The behavior, if someone forgot, is: take the first argument (a function from a
to b
) and apply it to every a
in the second argument list, finally return the resulting list.
You can see ($ 4)
as "pass 4 as argument to something". Which means that:
($ 4) func
is the same as:
func $ 4
So:
map ($ 4) [odd, even]
means:
[($ 4) odd, ($ 4) even]
[(odd $ 4), (even $ 4)]
[False, True]
Why (func $) is not necessary
You could argue that, just like you can do (/ 4)
and (2 /)
which respectively means "divide something by 4" and "divide 2 by something", you could do ($ 4)
and (func $)
and you would be right.
In fact:
(func $) 4
is the same as:
func $ 4
func 4
which is the same as:
($ 4) func
But the reality is that:
map (func $) [...]
would be unnecessary, since the first argument of map
is always applied to each argument to the list, making the above the same as:
map func [...]
Infix operators like *
, ++
, or $
typically take two arguments as in
x ++ y
When one argument is missing, and they are put between parentheses, they instead form a section:
(x ++)
(++ y)
These sections are equivalent to, respectively,
\y -> x ++ y
\x -> x ++ y
i.e., they stand for the function that maps the "missing argument" to the result. For instance,
map ("A"++) ["a","b"] == [ "Aa","Ab" ]
map (++"A") ["a","b"] == [ "aA","bA" ]
Operator $
is not special in this respect. We have
(f $)
($ x)
which stands for
\x -> f $ x
\f -> f $ x
The first is not very useful, since (f $)
is \x -> f $ x
which is (eta-)equivalent to just f
(*). The second is instead useful.
(*) To be picky, seq
can distinguish between undefined
and (undefined $)
, but this is a minor difference in practice.
$ 4 odd
: This won't work because operators must be surrounded by parentheses when not used in infix form. If you were to do ($) 4 odd
, this wouldn't work because argument order is incorrect, you want 4
to be the second argument. You could write ($) odd 4
though.
($ 4) odd
: This does work because it's using operator sections, and here the 4
is provided as the second argument to $
. It's like (++ "world") "hello "
being the same as "hello " ++ "world"
.
When you have ($ 4) :: Num a => (a -> b) -> b
, and odd :: Integral a => a -> Bool
, you just need to line up the types. Since every Integral a
is also a Num a
, we can just "upgrade" (constrain) the Num
to Integral
for this to work:
($ 4) :: Integral a => (a -> b) -> b
odd :: Integral a => a -> Bool
So a ~ a
and b ~ Bool
, so you can say that
($ 4) :: Integral a => (a -> Bool) -> Bool
So applying it to odd
gives us
($ 4) odd :: Bool
This is because ($ 4) odd
is the same as odd $ 4
. Looking at the definition of $
:
f $ x = f x
We can say that
odd $ 4 = odd 4
Which evaluates to False
.