TL;DR As others pointed out: the lambda notation is just a way to define functions without being forced to give them a name.
Long version
I would like to elaborate a bit on this topic because I find it very interesting. Disclaimer: I have taken my course on lambda calculus a long time ago. If someone with better knowledge finds any inaccuracies in my answer, feel free to help me improve it.
Let's start with expressions, e.g. 1 + 2
and x + 2
. Literals such as 1
and 2
are called constants because they are bound to specific fixed values.
An identifier such as x
is called variable and in order to evaluate it you need to bind it to some value first. So, basically you cannot evaluate x + 1
as long as you do not know what x
is.
The lambda notation provides a schema for binding specific input values to variables. A lambda expression can be formed by adding λx .
in front of an existing expression, e.g. λx . x + 1
. Variable x
is said to be free in x + 1
and bound in λx . x + 1
How does this help in evaluating expressions? If you feed a value to the lambda expression, like so
(λx . x + 1) 2
then you can evaluate the whole expression by replacing (binding) all occurrences of the variable x
with the value 2:
(λx . x + 1) 2
2 + 1
3
So, the lambda notation provides a general mechanism for binding things to variables that appear in an expression / program block. Depending on the context, this creates sightly different concepts in programming languages:
- In a purely functional language like Haskell, lambda expressions represent functions in the mathematical sense: an input value is injected into the body of the lambda and an output value is produced.
- In many languages (e.g. JavaScript, Python, Scheme) evaluating the body of a lambda expression can have side-effects. In this case one can use the term procedure to mark the difference wrt pure functions.
Apart from the differences, the lambda notation is about defining formal parameters and binding them to actual parameters.
The next step, is to give a function / procedure a name.
In several languages, functions are values like any other, so you can give a function a name as follows:
(define f (lambda (x) (+ x 1))) ;; Scheme
f = \x -> x + 1 -- Haskell
val f: (Int => Int) = x => x + 1 // Scala
var f = function(x) { return x + 1 } // JavaScript
f = lambda x: x + 1 # Python
As Eli Barzilay pointed out, these definition just bind the name f
to a value, which happens to be a function. So in this respect, functions, numbers, strings, characters are all values that can be bound to names in the same way:
(define n 42) ;; Scheme
n = 42 -- Haskell
val n: Int = 42 // Scala
var n = 42 // JavaScript
n = 42 # Python
In these languages you can also bind a function to a name using the more familiar (but equivalent) notation:
(define (f x) (+ x 1)) ;; Scheme
f x = x + 1 -- Haskell
def f(x: Int): Int = x + 1 // Scala
function f(x) { return x + 1 } // JavaScript
def f(x): return x + 1 # Python
Some languages, e.g. C, only support the latter notation for defining (named) functions.
Closures
Some final observations regarding closures. Consider the expression x + y
. This contains two free variables. If you bind x
using the lambda notation you get:
\x -> x + y
This is not (yet) a function because it still contains a free variable y
. You could make a function out of it by binding y
as well:
\x -> \y -> x + y
or
\x y -> x + y
which is just the same as the +
function.
But you can bind, say, y
in another way (*):
incrementBy y = \x -> x + y
The result of applying function incrementBy to a number is a closure, i.e. a function / procedure whose body contains a free variable (e.g. y
) that has been bound to a value from the environment in which the closure was defined.
So incrementBy 5
is the function (closure) that increments numbers by 5.
NOTE (*)
I am cheating a bit here:
incrementBy y = \x -> x + y
is equivalent to
incrementBy = \y -> \x -> x + y
so the binding mechanism is the same. Intuitively, I think of a closure as representing a chunk of a more complex lambda expression. When this representation is created, some of the bindings of the mother expression have already been set and the closure uses them later when it gets evaluated / invoked.
I wonder if 'lambda' has some esoteric meaning, seeing that the Greek letter lambda (λ) appears in so many avatars on this site.
One would hope it would be in reference to lambda calculus, but I have a strange feeling Half Life is to blame for lambda avatars.