Lambdas and composition
| Lambdas | |
| Composition | |
| Point-free style | |
| Where it hurts |
Lambdas
A lambda is a function without a name. The backslash stands in for the Greek letter, the arguments follow, and an arrow separates them from the body:
map (\x -> x * x) [1,2,3] -- [1,4,9]
filter (\s -> length s > 3) ["cat","horse"] -- ["horse"]
zipWith (\a b -> a * b) [1,2] [10,20] -- [10,40]
Use one when the function is short and used once. As soon as the same lambda appears twice, or it grows past one line, give it a name in a where block.
Composition
The dot operator joins two functions into one. It reads right to left, so the rightmost function runs first:
oddLength = odd . length
oddLength "abc" -- True
shout = map toUpper . filter (/= ' ')
shout "hi there" -- "HITHERE"
Composition is associative, so f . (g . h) and (f . g) . h are the same function. That is what lets a long pipeline be split across lines without changing its meaning.
Point-free style
When the last argument appears on both sides, it can be dropped. The result is called point-free, and it is a matter of taste, not of correctness:
-- with the argument named
total xs = sum (map (*2) xs)
-- the same function, point-free
total = sum . map (*2)
The second version says what the function is rather than what it does to an argument. It reads well for three or four steps and badly beyond that.
Where it hurts
Point-free style fails when an argument is used twice or in an unusual position. Fighting the compiler to remove a name is a sign that the name should stay:
-- clear
describe x = show x ++ " (" ++ show (x * 2) ++ ")"
-- unreadable, do not do this
describe = ((++) . (" (" ++) . show . (*2) . (")" ++)) . show
The second line is technically valid and practically hostile. Write
the version a colleague can read at two in the morning.
Next:
Type classes
Article author: Arthur Isaev