Currying and partial application
| One argument at a time | |
| Partial application | |
| flip and sections | |
| Why it matters |
One argument at a time
A function of two arguments is a function of one argument that returns a function. The arrow is right associative, so the signature below is the same as Int -> (Int -> Int):
add :: Int -> Int -> Int
add a b = a + b
-- add :: Int -> (Int -> Int)
Applying add to one number does not fail. It returns a function waiting for the second number.
Partial application
Supplying fewer arguments than a function expects is called partial application, and the result is a perfectly ordinary function:
addFive = add 5
addFive 3 -- 8
map (add 5) [1,2,3] -- [6,7,8]
This is why map takes a function and a list rather than a lambda: a half-applied function is usually exactly the function you need.
flip and sections
Order matters when you partially apply. flip swaps the first two arguments, and a section writes an operator with one side left open:
flip subtract 10 3 -- 7
map (10 -) [1,2,3] -- [9,8,7]
map (subtract 10) [1,2,3] -- [-9,-8,-7]
A left section fixes the left operand, a right section fixes the right one. The two lines above look similar and produce opposite results, which is the usual reason for a subtle bug.
Why it matters
Currying lets a general function become a specific one without defining anything new. A validator, a formatter, or a comparison arrives half-built and gets finished at the call site:
isLongerThan :: Int -> String -> Bool
isLongerThan n s = length s > n
filter (isLongerThan 3) ["cat", "horse", "ox"]
-- ["horse"]
The same trick scales to foldr and
traverse later. Learn to read a function as a
chain of one-argument steps and the rest of the course gets easier.
Next:
Operators, sections, and fixity
Article author: Arthur Isaev