Higher-order functions
Functions are our first kind of "glue" in Haskell.
Functions as first-class citizens
Haskell functions are first-class citizens of the language. This means that:
- We can name a function just as we can name any primitive value:
square = \x -> x * x
- We can pass functions to other functions:
map square [1, 3, 5, 7]
(Here,
map
is a higher-order function.) - Functions can produce other functions (here, by currying the
foldr
function):sum = foldr (+) 0
- Functions can form part of other data structures:
let fs = [(* 2), (* 3), (* 5)] zipWith (\f v -> f v) fs [1, 3, 5]
This places Haskell functions on an equal footing with primitive types.
Composing functions
Let's compose these three functions, f
, g
, and h
, in a few different ways:
f, g, h :: String -> String
The most rudimentary way of combining them is through nesting:
z x = f (g (h x))
Function composition gives us a more idiomatic way of combining functions:
z' x = (f . g . h) x
Finally, we can abandon any reference to arguments:
z'' = f . g . h
This leaves us with an expression consisting of only functions. This is the "point-free" form.
Programming with functions in this style, free of arguments, is called tacit programming.
It is hard to argue against the elegance of this style, but in practice, point-free style can be more fun to write than to read: it can become difficult to infer types (and, therefore, meaning). Use this style when ease of reading is not overly compromised.