How is $ used in higher order functions ? [duplicate] - haskell

This question already has answers here:
Why is `($ 4) (> 3)` equivalent to `4 > 3`?
(3 answers)
Closed 7 years ago.
This concerns an example encountered in Learn you a Haskell for Great Good, namely this one :
ghci> map ($ 3) [(4+), (10*), (^2), sqrt]
I'm trying to understand it but it makes no sense to me. Of course, the list of functions will be applied to the input (number 3) but I don't see how the $ operator helps. I'm trying to trace the order of application of things (if there's a haskell IDE with a step through compiler please let me know) and can't understand how $ being right associative allows flipping the function application, ie when I see map like this
map fun [1, 2 .. n]
I imagine the following happening to form the output list
fun 1
fun 2
.
.
fun n
but for the example at hand, how is this of meaning :
$3 4+

how is this of meaning :
$3 4+
That's not actually of meaning, indeed. But that's not what it simplifies to! It simplifies to
($3) (4+)
These things are operator sections.
($ 3) ≡ \x -> x $ 3
(4+) ≡ \x -> 4 + x
(10*) ≡ \x -> 10*x
(^2) ≡ \x -> x^2
so
($3) (4+) ≡ (\f -> f $ 3) (\y -> 4 + y)
≡ (\y -> 4 + y) $ 3
≡ (\y -> 4 + y) 3
≡ 4 + 3
Perhaps it's easier to understand if you visualise the “holes”:
map (□ $ 3) [(4+□), (10*□), (□^2), sqrt □]
≡ [(4+□) $ 3, (10*□) $ 3, (□^2) $ 3, (sqrt □) $ 3]
≡ [(4+3), (10*3), (3^2), (sqrt 3)]

The operator $ calls the function which is its left hand argument on the value which is its right hand argument. In the use of the example it "puts" the value 3 as additional argument of the sections in the list
Thus ($ 3) (4+) is (4+3). Analogously ($ 2) (4/) is (4/2)
The use of sections is easier to grasp using normal arithmetic operations. For instance: (/2) 4 is the same as 4/2 and thus 2

Related

Haskell: Understanding the map function when used with lambda function

I have the following two Haskell expressions:
map (\f x -> f x 5) [(-),(+),(*)]
map (\f x -> f 5 x) [(-),(+),(*)]
And I'm trying to figure out whether either expression above is equivalent to the following expression:
map ($ 5) [(-),(+),(*)]
I am trying to understand what the difference between the first two expressions is.
Since for both expressions, there is only one parameter passed to the lambda function (e.g. the operator), the function will be partially applied.
Is it correct to say that the elements in the result list from the first expression will be:
(1) - x 5 = (- x) 5
(2) + x 5 = (+ x) 5
(3) * x 5 = (* x) 5
And for the second expression:
(1) - 5 x = (- 5) x
(2) + 5 x = (+ 5) x
(3) * 5 x = (* 5) x
However, I don't think that either expression is equivalent to map ($ 5) [(-),(+),(*)]. This is because (- x) 5 (where x is a number) gives an error in GHCI and is an invalid expression. Similarly (- 5) x also gives an error.
On the other hand, map ($5) [(-)], results in a function that takes a number and subtracts it from 5.
Is this reasoning correct? Any insights are appreciated.
(- 5) 5 gives out an error because prefix minus is a special case in the language syntax: (- 5) means minus five, the number, and not a function that subtracts five (see also: Currying subtraction). That being so, I will focus on the (+) case, which is not exceptional.
In your second expression, map (\f x -> f 5 x) [(-),(+),(*)], the second element of the result list will be:
(\f x -> f 5 x) (+)
When evaluating such a thing by hand, it is important to be careful to not mix up prefix, infix and sectioned uses of operators. Application here gives out...
\x -> (+) 5 x -- Prefix syntax (note the parentheses around the operator)
... which is equivalent to...
\x -> 5 + x -- Infix syntax
... and to:
\x -> (5 +) x -- Left section
\x -> (+ x) 5 -- Right section
(5 +) -- Left section, pointfree
So the sections, which are patterned after infix usage of the operators, should be the other way around relative to your question. As for map ($ 5) [(-),(+),(*)], it is equivalent to map (\f x -> f 5 x) [(-),(+),(*)], your second expression. You can confirm that by using the fact that ($) f x = f x to figure out what the ($ 5) right section is.

How many times is (+ 1) computed here?

On my functional programming exam, I had the following question:
How many times is (+ 1) function computed in the following code?
(map (+ 1) [1 .. 10]) !! 5
where the index function is defined like this:
(h:_) !! 0 = h
(_:t) !! x = t !! (x-1)
I would say 6 times, but the correct answer seems to be 1, and I cannot understand why. I could not find a good enough explanation of lazy evaluation in Haskell, so I would like to know what is the correct answer and why. Thank you in advance!
many times is (+ 1) function computed in the following code?
It is calculated only once. map does not force to calculate f xi on the elements in the result list. These calculations are postponed (just like everything else in Haskell), only when we need to calculate the value of a specific item, we do that.
map is specified in chapter 9 of the Haskell'10 report as:
-- Map and append
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs
There are no seq, bang patterns, etc. here to force evaluation of f x, so the map function will indeed "yield" an f x, but without evaluating f x, it is postponed until it is necessary (and it might happen that we are not interested in some of these values, and thus can save some CPU cycles).
We can take a look how Haskell will evaluate this:
(!!) (map (+ 1) [1 .. 10]) 5
-> (!!) ((+1) 1 : map (+1) [2..10]) 5
-> (!!) (map (+1) [2..10]) 4
-> (!!) ((+1) 1 : map (+1) [3..10]) 4
-> (!!) (map (+1) [3..10]) 3
-> (!!) ((+1) 1 : map (+1) [4..10]) 3
-> (!!) (map (+1) [4..10]) 2
-> (!!) ((+1) 1 : map (+1) [5..10]) 2
-> (!!) (map (+1) [5..10]) 1
-> (!!) ((+1) 1 : map (+1) [6..10]) 1
-> (!!) (map (+1) [6..10]) 0
-> (!!) ((+1) 6 : map (+1) [7..10]) 0
-> (+1) 6
-> 7
This is because map f [x1, x2, ..., xn] eventually maps to a list [f x1, f x2, ..., f xn], but it does not compute f xi of the elements, that computation is postponed until we actually would need the value in that list, and do something with it (like priting it).
This can result in a significant performance boost, given f is an expensive function, and we only need the value of a small amount of elements in the list.
Let's test it by doing something horrible. You'll need to import the Debug.Trace module for this.
ghci> (map (\x -> trace "Performing..." (x + 1)) [1..10]) !! 5
Now, we'll get that totally safe IO action to happen every time the lambda expression is called. When we run this in GHCi, we get
Performing
7
So only once.
As a sanity check, we could remove the !! 5 bit.
ghci> map (\x -> trace "Performing..." (x + 1)) [1..10]
[Performing
2,Performing
3,Performing
4,Performing
5,Performing
6,Performing
7,Performing
8,Performing
9,Performing
10,Performing
11]
So it's definitely happening 10 times when we ask for the whole list.

Treating "$" as function application

I encountered this example while reading Learn You a Haskell for Great Good.
ghci> map ($ 3) [(4+), (10*), (^2), sqrt]
[7.0,30.0,9.0,1.7320508075688772]
I don't quite see how to treat $ as function application. Does that mean $ is an operator? But if so, how it will be nested with + or * in the example? I tried $ 3 4+, $ 4 + 3, but both raised parse error on input ‘$’. How to think of an expression like this in functional programming context?
$ is indeed an operator, defined as:
f $ x = f x
-- or equivalently:
($) f x = f x
Your expression above is equivalent (by the definition of map) to:
[($ 3) (4 +), ($ 3) (10 *), ($ 3) sqrt]
The parentheses in ($ 3) and (4 +) are not optional. They're part of what's called an operator section. Basically, there are four ways you can use an infix operator (such as +):
Between two arguments:
x + y
Only giving the first argument:
(x +)
-- like \y -> x + y
Only giving the second argument:
(+ y)
-- like \x -> x + y
No arguments:
(+)
-- like \x y -> x + y
($ 3) f evaluates to f $ 3 evaluates to f 3.
($ 3) (4 +) evaluates to (4 +) $ 3 evaluates to (4 +) 3 evaluates to 4 + 3 evaluates to 7.

Confusion about the $ operator and parentheses

I'm working my way through the first haskell book and struggle with the $ operator:
The following line works:
map (>= 16) . take 5 $ iterate (\x -> x^2) 2
However, the following doesn't:
map (>= 16) . take 5 (iterate (\x -> x^2) 2)
Possible cause: `take' is applied to too many arguments
I don't see the problem here. take takes an int and a list. To my understanding, I provided both arguments.
What do I have to do if I want to avoid the $ operator?
The ($) :: (a -> b) -> a -> b operator is a function that simply has a the lowest priority (infixr 0, only ($!) and seq have the same priority). As a result:
map (>= 16) . take 5 $ iterate (\x -> x^2) 2
is equivalent to:
(map (>= 16) . take 5) (iterate (\x -> x^2) 2)
so also with brackets for the left operand as well.
It is actually a nice thing about Haskell that you can use operators as a grouping mechanism: ($) is simply defined as ($) f x = f x, but because of the fact that it is an operator, it can be used as a way to avoid brackets.

Partial application of functions and currying, how to make a better code instead of a lot of maps?

I am a beginner at Haskell and I am trying to grasp it.
I am having the following problem:
I have a function that gets 5 parameters, lets say
f x y w z a = x - y - w - z - a
And I would like to apply it while only changing the variable x from 1 to 10 whereas y, w, z and a will always be the same. The implementation I achieved was the following but I think there must be a better way.
Let's say I would like to use:
x from 1 to 10
y = 1
w = 2
z = 3
a = 4
Accordingly to this I managed to apply the function as following:
map ($ 4) $ map ($ 3) $ map ($ 2) $ map ($ 1) (map f [1..10])
I think there must be a better way to apply a lot of missing parameters to partially applied functions without having to use too many maps.
All the suggestions so far are good. Here's another, which might seem a bit weird at first, but turns out to be quite handy in lots of other situations.
Some type-forming operators, like [], which is the operator which maps a type of elements, e.g. Int to the type of lists of those elements, [Int], have the property of being Applicative. For lists, that means there is some way, denoted by the operator, <*>, pronounced "apply", to turn lists of functions and lists of arguments into lists of results.
(<*>) :: [s -> t] -> [s] -> [t] -- one instance of the general type of <*>
rather than your ordinary application, given by a blank space, or a $
($) :: (s -> t) -> s -> t
The upshot is that we can do ordinary functional programming with lists of things instead of things: we sometimes call it "programming in the list idiom". The only other ingredient is that, to cope with the situation when some of our components are individual things, we need an extra gadget
pure :: x -> [x] -- again, one instance of the general scheme
which wraps a thing up as a list, to be compatible with <*>. That is pure moves an ordinary value into the applicative idiom.
For lists, pure just makes a singleton list and <*> produces the result of every pairwise application of one of the functions to one of the arguments. In particular
pure f <*> [1..10] :: [Int -> Int -> Int -> Int -> Int]
is a list of functions (just like map f [1..10]) which can be used with <*> again. The rest of your arguments for f are not listy, so you need to pure them.
pure f <*> [1..10] <*> pure 1 <*> pure 2 <*> pure 3 <*> pure 4
For lists, this gives
[f] <*> [1..10] <*> [1] <*> [2] <*> [3] <*> [4]
i.e. the list of ways to make an application from the f, one of the [1..10], the 1, the 2, the 3 and the 4.
The opening pure f <*> s is so common, it's abbreviated f <$> s, so
f <$> [1..10] <*> [1] <*> [2] <*> [3] <*> [4]
is what would typically be written. If you can filter out the <$>, pure and <*> noise, it kind of looks like the application you had in mind. The extra punctuation is only necessary because Haskell can't tell the difference between a listy computation of a bunch of functions or arguments and a non-listy computation of what's intended as a single value but happens to be a list. At least, however, the components are in the order you started with, so you see more easily what's going on.
Esoterica. (1) in my (not very) private dialect of Haskell, the above would be
(|f [1..10] (|1|) (|2|) (|3|) (|4|)|)
where each idiom bracket, (|f a1 a2 ... an|) represents the application of a pure function to zero or more arguments which live in the idiom. It's just a way to write
pure f <*> a1 <*> a2 ... <*> an
Idris has idiom brackets, but Haskell hasn't added them. Yet.
(2) In languages with algebraic effects, the idiom of nondeterministic computation is not the same thing (to the typechecker) as the data type of lists, although you can easily convert between the two. The program becomes
f (range 1 10) 2 3 4
where range nondeterministically chooses a value between the given lower and upper bounds. So, nondetermism is treated as a local side-effect, not a data structure, enabling operations for failure and choice. You can wrap nondeterministic computations in a handler which give meanings to those operations, and one such handler might generate the list of all solutions. That's to say, the extra notation to explain what's going on is pushed to the boundary, rather than peppered through the entire interior, like those <*> and pure.
Managing the boundaries of things rather than their interiors is one of the few good ideas our species has managed to have. But at least we can have it over and over again. It's why we farm instead of hunting. It's why we prefer static type checking to dynamic tag checking. And so on...
Others have shown ways you can do it, but I think it's useful to show how to transform your version into something a little nicer. You wrote
map ($ 4) $ map ($ 3) $ map ($ 2) $ map ($ 1) (map f [1..10])
map obeys two fundamental laws:
map id = id. That is, if you map the identity function over any list, you'll get back the same list.
For any f and g, map f . map g = map (f . g). That is, mapping over a list with one function and then another one is the same as mapping over it with the composition of those two functions.
The second map law is the one we want to apply here.
map ($ 4) $ map ($ 3) $ map ($ 2) $ map ($ 1) (map f [1..10])
=
map ($ 4) . map ($ 3) . map ($ 2) . map ($ 1) . map f $ [1..10]
=
map (($ 4) . ($ 3) . ($ 2) . ($ 1) . f) [1..10]
What does ($ a) . ($ b) do? \x -> ($ a) $ ($ b) x = \x -> ($ a) $ x b = \x -> x b a. What about ($ a) . ($ b) . ($ c)? That's (\x -> x b a) . ($ c) = \y -> (\x -> x b a) $ ($ c) y = \y -> y c b a. The pattern now should be clear: ($ a) . ($ b) ... ($ y) = \z -> z y x ... c b a. So ultimately, we get
map ((\z -> z 1 2 3 4) . f) [1..10]
=
map (\w -> (\z -> z 1 2 3 4) (f w)) [1..10]
=
map (\w -> f w 1 2 3 4) [1..10]
=
map (\x -> ($ 4) $ ($ 3) $ ($ 2) $ ($ 1) $ f x) [1..10]
In addition to what the other answers say, it might be a good idea to reorder the parameters of your function, especially x is usually the parameter that you vary over like that:
f y w z a x = x - y - w - z - a
If you make it so that the x parameter comes last, you can just write
map (f 1 2 3 4) [1..10]
This won't work in all circumstances of course, but it is good to see what parameters are more likely to vary over a series of calls and put them towards the end of the argument list and parameters that tend to stay the same towards the start. When you do this, currying and partial application will usually help you out more than they would otherwise.
Assuming you don't mind variables you simply define a new function that takes x and calls f. If you don't have a function definition there (you can generally use let or where) you can use a lambda instead.
f' x = f x 1 2 3 4
Or with a lambda
\x -> f x 1 2 3 4
Currying won't do you any good here, because the argument you want to vary (enumerate) isn't the last one. Instead, try something like this.
map (\x -> f x 1 2 3 4) [1..10]
The general solution in this situation is a lambda:
\x -> f x 1 2 3 4
however, if you're seeing yourself doing this very often, with the same argument, it would make sense to move that argument to be the last argument instead:
\x -> f 1 2 3 4 x
in which case currying applies perfectly well and you can just replace the above expression with
f 1 2 3 4
so in turn you could write:
map (f 1 2 3 4) [1..10]

Resources