Function application in Haskell

811 views Asked by At

OK, it's been a long day and my brain may not function at Haskell level, but I just cannot understand one example from 'Learn You a Haskell'.

The section is called Function Application with $, and there is example of how $ may be defined:

($) :: (a -> b) -> a -> b
f $ x = f x

So far everything is clear. I understand all examples in the section, except for the last one:

ghci> map ($ 3) [(4+), (10*), (^2), sqrt]
[7.0,30.0,9.0,1.7320508075688772]

Here we map ($ 3) across list of functions and get result of application of those functions to 3. But how is this possible?

From the first code snippet it's clear that first argument is a function, we can even write:

*Main> ($) sqrt 4
2.0

Now ($ 3) is a partial application of function $, but 3 goes on function's position! So 3 is supposed to be a function or what?

There is another mystery: what the heck is (4+)? I know that (+4) is a partial application of function +, so (4+) should be partial application of function 4? Nonsense. What sort of trick works here?

3

There are 3 answers

0
sepp2k On BEST ANSWER

($ 3) and (+ 4) aren't partial applications - they're operator sections. A partial application would look like (($) 3) or ((+) 4).

An operator section of the form (? x) (where ? stands for an arbitrary infix operator) binds the right operand of the operator, i.e. it is equivalent to \y -> y ? x. Likewise the operator section (x ?) binds the left operand and is thus equivalent to partial application.

2
bheklilr On

I think what's tripping you up is operator sections. These let you partially apply an operator with either one of its arguments, so you can have the operators (+4) and (4+), where 4 is the the second then the first argument to + respectively. A more clear example might be ("Hello" ++) versus (++ "world"), the former prepends "Hello" onto the front of a string, while the latter appends "world" onto the end of a string.

This is contrasted with using operators in prefix form with just parens around it. In this form, the following are equivalent:

> let join = (++)
> join "Hello, " "world"
"Hello, world"
> (++) "Hello, " "world"
"Hello, world"

In prefix form, you treat the operator as a normal function and it accepts its first then second argument in order. In operator sections, it matters which side of the operator the argument is on.


So in your example, you have the partial application of ($ 3), you can reduce it as

map ($ 3) [(4+), (10*), (^2), sqrt]
[($ 3) (4+), ($ 3) (10 *), ($ 3) (^ 2), ($ 3) sqrt]
[4 + 3, 10 * 3, 3 ^ 2, sqrt 3]
[7.0, 30.0, 9.0, 1.7320508075688772]
0
Sibi On

You are getting confused with sections. A good way to grasp the concept of sections is playing with an example:

(<^>) :: Int -> Float -> Int
a <^> b = a

The above function is an useless function which returns the first parameter no matter what the second parameter is. But it accepts Int and then Float as input.

Now, because of sections you can apply with any one of their arguments:

λ> let a = (3 <^>)
λ> :t a
a :: Float -> Int
λ> let b = (<^> 3.0)
λ> :t b
b :: Int -> Int

See how the type of a and b are different because of sections.