The heart of functional programming is that programs, i.e., functions, can manipulate other functions. That some functions can produce functions as output seems to be one of the hardest concepts for some students. Over and over I talk to students who resist that idea.
Most students are comfortable with using a function to produce another function, which is then applied to arguments. For example,
> flip (:) [1, 2, 3] 0
[0,1,2,3]
The flip
function takes a function as its argument and produces another function. That output function acts like the original function but with the arguments reversed. [As a side note, think about the associativity of the expression above. The implicit parenthesizing is like this: (flip (:)) [1, 2, 3] 0
. It wouldn't work if it were like this: flip ((:) [1, 2, 3] 0)
.
But many students are not comfortable talking about the output of a function like flip
without talking about it being applied to arguments. Here is the type of flip
.
> :t flip
flip :: (a -> b -> c) -> b -> a -> c
The best way to read this is as follows.
> :t flip
flip :: (a -> b -> c) -> (b -> a -> c)
The input to flip
is a function that takes two arguments of type a
and b
respectively and produces a result of type c
. The output of flip
is also a function. It takes two arguments of type b
and a
respectively and produces a result of type c
. flip
is defined as follows.
flip f = \y x -> f x y
In other words, the output of flip
is a lambda function. It is a function that can be applied to arguments. But even when it's not applied to arguments, it's a thing in the program. It can be assigned to a variable, e.g., > h = flip (:)
. It can be described in terms of its arguments and its result, just like any other function. You can say that h
is a function that takes two arguments. The first is a list; the second is an element of the same type as the list elements. Here is the type of h
.
> :t h
h :: [a] -> a -> [a]
When applied to arguments h
creates a new list whose head is its second argument and whose tail is its first argument.
> h [1, 2, 3] 0
[0,1,2,3]
I want you to be able to think in those terms. In functional programming some programs can take a function as an argument (the way map
does) and (even more important) can produce a function (which will necessarily be a lambda function) as its output. You should be comfortable with concepts of that sort.