In this article, we will explore the basics of λ-calculus and how to evaluate cool expressions with pLam.

The source code, examples and documentation for pLam can be found here at GitHub

What is λ-calculus?

λ-calculus is a formal system for expressing computation via function abstraction and application. Much like Turing Machine is a (more famous) framework for expressing computation, so is λ-calculus. Both of them are universal models of computation (i.e. they are equivalent in power) and can simulate each other.

It was invented by Alonzo Church in the 1930s as an attempt to formalize mathematics and to answer the question “Can everything be computed?”. I will not go into historical details of this quest for truth, but the answer to the question is “no”. There are things that are not computable. Interested reader can learn more about those topics starting, for example, at Wikipedia page about Computability.

In later years, Church’s student Alan Turing came up with the idea of modeling computation with some more machine-like apparatus for which they together proved it was equivalent in power to λ-calculus. Turing’s idea was the foundation for building a modern computer architecture and a basis for imperative programming languages (C, C++, Java, Python, …) which all use statements that change some shared global memory.

On the other hand, λ-calculus became a foundation for functional programming languages (Lisp, Haskell, …) that compute by composing and applying functions. Many imperative languages today have support for functional style programming with “anonymous functions”.

Syntax and semantics of λ-calculus

There are only 3 entities in λ-calculus; variable, abstraction and application. We call them λ-expressions.

variable is represented with single character, e.q. x .

. abstraction is a definition of a function and is written as λx. L , where x is a variable (“the input”) and L is some λ-expression (the body, “the output”). You can think of it like a mathematical function f(x) = L , where L can be something like x+5 , i.e. the part you “get” when you plug in something for x .

, where x is a variable (“the input”) and is some λ-expression (the body, “the output”). You can think of it like a mathematical function , where can be something like , i.e. the part you “get” when you plug in something for . application is two λ-expressions side-by-side, written as M N , meaning that M is applied to N . Application is left associative, i.e. X Y Z means (X Y) Z

The procedure of computation in λ-calculus is done by a rewriting rule called β-reduction. It is performed when we have an application where first expression ( M ) is an abstraction. Then, the second member of application ( N ) gets replaced into abstractions’s body in place of abstraction’s variable ( x ) contained (if at all) inside abstraction’s body ( L ).

You can think of it like plugging a value into a function. For example, let's take f(x) = x + 5 and we want to plug the value 3 for x . Writing it more in the syntax of λ-calculus calculus, we would have (λx. x+5) 3 which is an application ( M = (λx. x+5) and N = 3 ) of abstraction (variable is x and body is x+5 ) to the 3 . β-reduction rule tells us that we reduce this by taking the body of abstraction ( x+5 ) and replacing occurrences of x with 3 . We get 3+5 .

And this is it. We don’t go further with this example because object 3+5 is not λ-expression and there is nothing to do here regarding λ-calculus. It was just an example of how λ-calculus computes by replacing variables with λ-expressions.

Another example; (λx. (x y x)) N gets β-reduced into (N y N)

I will stop here with λ-calculus because I intended this article to be more about pLam, with the assumption that readers are familiar enough with λ-calculus. Nevertheless, you can continue reading more about λ-calculus here at Wikipedia if interested. That Wikipedia page about λ-calculus is a great resource and I personally started my learning about the topic there.