Functional languages are currently rediscovered, due to scalability
issues and multicore processors, among other things. Several functional
concepts, often unfamiliar to the developer accustomed to more classical
languages, are becoming widespread. Here and there, you see more and more
references to lambda, closure, or even partials or
currying.
This article purpose is to rapidly present these concepts, without
dealing with all their power, to allow newcomers in functional land to not be
lost. May purists forgive me for shortcomings and simplifications.
Lambdas, whose name comes from λ-calculus, are one
of the theoretical foundations of functional languages. Left aside syntactic
sugar, they are no more than anonymous functions.
In functional context, functions are natural values, and can be put
into variables (or symbols), passed around, and returned (by higher-order
functions). They are called first class values (no connection
with object oriented programming, rather with trains).
One of the benefits of a lambda with respect to a “classical”
function, is that it can be created on demand, in a local scope, and can be
garbage collected when not in use. This aspect is useful with functional
paradigms, which make heavy use of higher-order functions (composing, list
manipulations with map, filter and
reduce), as in events oriented programming, where a function is
directly added to the event handler. In most of these cases, these functions
are “one shot”, and it is therefore easier to define them as lambda.
In some languages, a lambda must be functionally pure,
that is return a value only depending on the input, and have no side effects.
The function application can thus always be replaced by its returned value
without changing program semantic (called referential transparency).
The return keyword can therefore be omitted, and the function call
is considered as an expression, bringing syntactic sugar: the function can be
written as a mathematic function (this aspect is true for all functions, not
only lambda, in purely functional languages).
The following snippets are comparing the classical function
definition with the one using lambda.
In some functional languages, this distinction is meaningless.
As an example, O’Caml’s first definition is just syntactic sugar for the
second one. The same is true for Scheme and Javascript.
Formally, a closure is embedding external value references
inside a function definition.
This is usually done with a higher-order function returning a
function whose defining depends on given values.
In these examples, the a variable is closed
in the anonymous function returned. A call to adder returns a
newly created function, usable as any other function.
The adder function defines a functions set,
parametrised by a.
Note that you don’t have to affect the returned function, it can be
used directly as adder(21)(21).
In a sens, closures are a dual form of objects oriented
programming, where behaviour (methods) is embedded in data structure. Here,
the data (closed value) is are embedded in the behaviour. These two approaches
define a family of processing units parameterized by their state. Instead of
creating a new class instance, each closure call creates a new function
(function factory).
It’s a way to emulate closures in OO languages: a callable (inner)
class whose private attribute represents the closed value, as shown below in
Python, which is functionally equivalent to the previous closure.
Even if lambda are often used to create closures, it’s not
necessary if the language as inner functions:
Concerning the garbage collector: creating a closure on a variable
create a reference to it, in the anonymous function. As long as this function
persists, the variable will not be collected, even if it’s initial scope is
terminated (it’s this feature that allow the closures themselves).
Usage Example
Standard example in event-based programming to easily create series
of similar handlers.
We have here a function displaying a message. We can’t use it as a
handler, since a handler must take the event as single argument. The closure
handleWithMessage use the message to display to create a new
function usable as a handler. The message is closed in the function definition
(to be strict, the closure is the returned function, not
handleWithMessage which is rather a factory).
Partial function application binds one or more arguments
of a polyadic function, giving a new function with a simplified
signature. This is equivalent to create a closure of an existing function on
one or several of its arguments.
In languages with undefined arguments number, a generic partializing
function is easy to create. Otherwise, a function must be defined for every
function arity, which can be tedious.
In languages with named arguments, it is possible to partialize any
argument, not only positional ones. Python provides a generic function
(functools.partial, which is created by hand here for
demonstration), as well as Golo (:bindWith).
Those used to functional programming can note that to
partialize easily a function, one can reduce the arguments list with the
partializing function. In Python for example, one can write
superadd = reduce(partialize, [14,14], add3).
I’ll write more extensively about reduce, as well as map as
seen above (map, reduce, reminds you something?), in another article.
The above Caml (and Haskell) example is a purely didactic one, since this
language allow to directly partialize any function. Calling it with less
arguments as needed automatically returns a partial function.
Since addition is just an infix function, this can be even easier
as in the last snippets.
In Caml, as in other ML languages, Haskell, and others, functions
are auto-curryfied. That is, a function with several arguments is
actually a function with a single argument, that returns a function with a
single argument, and so on. As an example, the addition signature is add
: int → int → int, which can be written add : int → (int →
int) (that is a function on integer returning a function on integer
returning an integer).
Curryfying a function (from the mathematician Haskell Curry, who
also named the functional language), means transforming it in a chain of single
argument functions, or simply making it automatically partialing.
This is the same as defining the function as a chain of lambda,
each one being a closure on the previous one’s argument.
Therefore, it is no more required to partialize these functions,
since calling them with too few arguments will return a partially applied function.
Again, it is easy to write an auto-currying function, that is a
function taking a function as argument and returning a curryfied version of it
(left as an exercise).
To conclude
I hope these concepts are now clearer to you. If you have remarks
or questions, do not hesitate to ask me.
I’ll probably continue to improve this article, specially by adding
more snippets in other languages; I like such comparisons, that helps to show
concepts beyond syntax and language specificities.
I made a follow up to this
article, dealing with simulating these concepts in Java.
References
If you mind explore a little more these languages: