The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

317529 (6) [Avatar] Offline
#1
I've been working through the v2 book, and I saw the following code in a listing in section 8.3:

map ("a "++) ["train","plane","boat"]
map (^2) [1,2,3]


The functions (i.e., ("a " ++) and (^2)) were written in a way that didn't look familiar to me. I tried a few other things like:

filter (<3) [2,3,4]
filter (/=' ') "Hello world"


I was delighted to discover that those work! Are these just instances of Partial Application with infix functions that look like operators? Or is there something else going on here?

Thanks for your help!
Will Kurt (21) [Avatar] Offline
#2
Your intuition is correct, these are just cases of Partial application with Binary operators! In Haskell binary operators are just a special case of a regular binary function where the function happens to be in the middle of two arguments. In fact if you want you can treat any binary operator like a regular function by wrapping it in parentheses.

For example
2 + 4

can also be written as
(+) 2 4


To demonstrate this better we can use a function where the order of the arguments matters.

For this bit of code
map (/ 2) [1,2,4]

we're missing the left-most argument, ie this translates to:
[(1 / 2),(2 / 2), (4 / 2)]

So we get the following result:
[0.5,1.0,2.0]


But if we wrap / in parentheses, changing it from an operator to a function like this:
map ((/) 2) [1,2,4]

Then we're missing the right-most argument which translates to:
[((/) 2 1),((/) 2 2),((/) 2 4)]

Giving us the opposite result as the previous example!
[2.0,1.0,0.5]


The ++ operator has a similar property:
Prelude> map (++ "s") ["car","pot","ack"]
["cars","pots","acks"]
Prelude> map ((++) "s") ["car","pot","ack"]
["scar","spot","sack"]


An alternate way of indicating that the right-most argument is missing would be to use the regular binary operator syntax and supply only the left argument:
Prelude> map ("s" ++) ["car","pot","ack"]
["scar","spot","sack"]


To summarize, for partial application with a binary operator we have three ways we can indicate a missing argument. Below ++ is our operator, 'x' will be our argument and '?' will indicate the missing argument that partial application is waiting for

(++ x) means (? ++ x)
(x ++) means (x ++ ?)
((++) x) means ((++) x ?)

Hope that helps clarify things! If you have a good sense of how partial application works with binary operators, then I would say you've got partial application down!


317529 (6) [Avatar] Offline
#3
Ah, yes -- that's a very clear explanation, and it totally makes sense now. Thanks for taking the time to walk me through it!
Mark Elston (133) [Avatar] Offline
#4
There is a problem I have with this description. In chapter 4 you state (start of section 4.3):

Partial Application is also the reason we created the rule that arguments should be ordered from most to least general. When we use Partial Application the arguments are applied first to last.


But you said (above) that in

map (/ 2) [1,2,4]


we are missing the left-most argument and this translates to:

[(1 / 2),(2 / 2), (4 / 2)]


From what you said in the book it would appear that the '2' should be applied as the first argument to the '/' operator, not the second. How do these two things square?

I ran into this with listing 14.5 and couldn't figure out how the list (which is supposed to be the 2nd argument) was partially applied to the elem function without applying it as the first argument.
Mark Elston (133) [Avatar] Offline
#5
Well, just after I posted this question I found this on StackOverflow and this on the Haskell wiki. The short answer is this is called a 'Section of an infix operator'. In particular these examples show a 'right section' (with the second argument partially applied).

I had no idea you could do this.

And it wasn't explained in the book. You might want to add a description of this before you make use of it... Just sayin'.
Will Kurt (21) [Avatar] Offline
#6
I can definitely see where this is confusing (and actually just started to type out an example where it was clear the logic fails). I'll definitely add a section to partial application explaining how it works for binary operators. Again, thanks for your feedback and making this a better book!