What is it

Lambda calculus was originally created by Alonzo Church. It is the world’s smallest programming language. While it does not have numbers, strings, booleans, or any non-function datatype, it can represent any Turing machine.

Lambda calculus has 3 elements:

Motivation

Functions exist, i.e

\[ square\_sum(x, y) = x^{2} + y^{2} \]

This can be understood as, "a tuple of x and y maps to \(x^{2} + y^{2}\). Well, with that being said:

\[ id(x) = x \]

can be rewritten to its anonymous form, which is

\[ x \mapsto x \]

This is supposed to demonstrate the fact that lambda calculus only uses functions with a single input. Functions that require more than one can be rewritten to functions with one argument, but return another function, which also then returns a single input. For example:

\[ (x, y) \mapsto x^{2} + y^{2} \]

can be reworked into

\[ x \mapsto ( y \mapsto x^{2} + y^{2} ) \]

This is known as currying: transforming a function that takes multiple arguments into a chain of functions each with a single argument. Below is a expanded function application of a curried function as an example.

\[ \begin{aligned} & ((x \mapsto ( y \mapsto x^{2} + y^{2} ))(5))(2) \\ & = (y \mapsto 5^{2} + y^{2})(2) \\ & = 5^{2} + 2^{2} \\ & = 29 \end{aligned} \]

The Lambda Calculus

Lambda calculus consists of lambda terms and transformation rules which allow for manipulation of the terms. Functions in lambda calculus are anonymous (not named). They take in only one variable and leverage currying to implement functions that would otherwise use multiple variables.

What is a lambda term? A lambda term is defined as a valid lambda calculus expression. There are a few rules that allow you to precisely verify whether something conforms to lambda term syntax, however, the basic gist is that the syntax is composed of the 3 elements outlined earlier: variables, abstractions (functions), and applications (think of invoking functions). Nothing else is a lambda term.

What is an abstraction? An abstraction \(\lambda x.t\) is an anonymous function that takes a single input, replacing the body (expression \(t\)) with the input where it occurs. The function/abstraction just sets up the function, it does not invoke it.. The abstraction \(\text{\underline{binds}}\) the variable \(x\) in the term \(t\).

What is an application? An application is simply the calling of a function.

There is no concept of variable declaration in lambda calculus. Dangling “variables” are just unknown values.

Functions in lambda calculus are first-class values. What does this mean? It means you can use the functions as inputs and outputs from other functions. It’s also worth noting that function application in lambda calculus is left-associative, this means stx would act as (st)x.

Reductions

Lambda calculus consists of constructing lambda terms and performing reduction operations on them. There are two types of reduction.

Names Descriptions
\(\alpha\) conversion Renaming the bound variables in the expression. Used to avoid naming collisions
\(\beta\) reduction Replacing the bound variables with the argument expression in the body of the abstraction.

Alpha Equivalence

The idea behind alpha equivalence merely is that the naming of variables in abstractions doesn’t really matter. Variables by themselves, though, such as x and y are not said to be alpha-equivalent since they are not bound in an abstraction where they would evaluate to the same expression.

Beta Reductions

It is important to note a few terms before defining \(\beta\)-Reduction.

  • Free variables
    • What are these? These are just regular variables that aren’t part of an abstraction’s input. So really it’s just the variables that are part of the actual expression of the abstraction minus the input variables.
  • Capture-avoiding substitutions
    • The intuition behind this one is just to avoid naming collisions.
    • The notation \(t[x := r]\) is a notation that indicates the substitution of \(r\) for \(x\) in \(t\).
    • If a rename is done to a name that is not part of the free variables or the input, it is said to meet the freshness condition because there aren’t naming collisions then.

Ok, so what are \(\beta\)-reductions?. The \(\beta\)-reduction is simply stating that: \((\lambda x, t)s\) reduces to \(t[x := s]\), which simply means replace the body \(t\) that has any input \(x\) with the value passed in from the invocation \(s\).

This may remind you of functional programming languages like OCaml. It’s almost like a computation. It seems beta reductions can be applied continuously such that it eventually terminates. Though, it is very possible to have an abstraction such as \((\beta x, xx)\), where subsequent beta reductions would never terminate the reduction process. This is a property of untyped lambda calculus, but not typed lambda calculus. Another difference between these two types of lambda calculus is that untyped lambda calculus doesn’t care what kind of data it’s working with. Typed lambda calculus does, i.e. if you wanted an abstraction that only worked on numbers. In untyped lambda calculus there is no way to constrain it to certain types of inputs.

Combinators

Combinators are simply \(\lambda\)-terms that do not have free variables. There are a few special combinators. Here are some:

References

Wikipedia

Stanford Encyclopedia of Philosophy

Medium Article on the Y Combinator