Function application in Haskell
Asked Answered
A

3

9

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?

Avalos answered 8/9, 2014 at 14:50 Comment(1)
possible duplicate of Partial Application with Infix FunctionsFeller
I
14

($ 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.

Ivonne answered 8/9, 2014 at 14:59 Comment(0)
B
9

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]
Bournemouth answered 8/9, 2014 at 14:58 Comment(2)
"you treat the operator as a normal function", I thought that 'operators' are normal functions in Haskell.Avalos
@Mark they're normal in every respect other than their syntax for application. They're by default infix, while a non operator function is by default prefix. When I say normal function, I mean a prefix function.Bournemouth
W
4

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.

Workman answered 8/9, 2014 at 15:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.