Lamdba calculus has three expressions:

variable : x

: x lambda abstraction (function): λx.x (where . separates the function argument (λx) and body (x))

(function): λx.x (where . separates the function argument (λx) and body (x)) function application: (M N) — we apply one lambda expression to another, here we apply M to N.

So instead of traditional math expressions, or symbols (+, -, =), or formal logic symbols (->, =>, !=), you just use the above expressions (variables, abstraction, and application) to evaluate an argument.

We write a lambda expression for each function. Input and output are also lambda expressions. Also (by convention) application is left associative: ABC means (AB)C not A(BC), and application has higher precedence than abstraction: λx.AB means λx.(AB), not (λx.A)B

Thus, in algebra, you say “2 + 3” for adding 2 and 3. In Lambda Calculus, you would say something like “(λsz.s(sz))(λwyx.y(wyx))(λuv.u(u(uv)))”

Where 2 + 3 has three functions:

λsz.s(sz)) — This is a function representing the number two

λwyx.y(wyx) — This is a successor function that takes an input and returns the next succeeding value

λuv.u(u(uv)) — This is a function representing the number three

Let’s evaluate this together to see some of the theory behind Lambda Calculus applied:

(λsz.s(sz))(λwyx.y(wyx))(λuv.u(u(uv)))

2 + 3 where each variable and function is a variable/function

Can be reduced to:

(λwyx.y((wy)x))((λwyx.y((wy)x))(λuv.u(u(uv))))

Let’s hit the replay button and see that again in slow motion:

λsz.s(sz) — This is the number 2 in Lambda calculus. The λ is the Greek letter Lamba and it’s used to denote a function.

This can be read something like “there is function such that it takes inputs s and z in such a way that s(sz)”. Although I really don’t know how to read it. Maybe someone can help?

Because there’s no numbers or math symbols in Lambda calculus, the “value” of the numeral is equivalent to the number of times the function encapsulates its argument..

A moment of thought, the fact that the “value” of a number depends on its ability to serve as a variable just shows how pragmatic the function/variable dynamic is. The only way to determine the value of something is to be able to (pragmatically) use it to propel another function to reduce. We’ll learn more about Lambda reductions later on but it’s important to remember that a function is always anonymous in Lambda calculus and defined in the moment of evaluation.

Every time you do addition, we write down the actual function that will be used to evaluate the addition (ie λwyx.y((wy)x)). You then associate this function with the values you want to put in that function (λsz.s(sz) [the number two], and λuv.u(u(uv)) [the number three]); which again are further functions. And the value is determined by the number of iteration that we can carry out with those functions; denoted by the variable we choose. In this case ‘y’. I’m going to tie these concepts to CS Peirce’s pragmatism later on (or try to).

Thus in λsz.s(sz), the z in (s(sz)) can be seen as zero and each of the two s’s (s(sz)) can be see as one iteration of the successor function. Since there are two successions (s), the value the function represents is two. This can be seen in the fact that after we evaluated λsz.s(sz), we ended up with two instances of this successor function: λwyx.y(wyx). Let’s see that again.

Keep in mind that we evaluate functions from left to right, after being led by parentheses (like in other maths), so we first evaluate this guy: λsz.s(sz)

This guy takes two arguments (s, z) and replaces one s outside the parenthesis and the s z pair inside the parentheses.

In this case:

s = λwyx.y((wy)x)

z = λuv.u(u(uv))

The reason that s and z represent those functions is that the problem to begin with was: (λsz.s(sz))(λwyx.y(wyx))(λuv.u(u(uv)))

I don’t know how to explain it exactly but you see how each function is separated by parenthesis (bold)? Since there’s two variable/functions that come after the function that calls for variables s and z, we just map that to the following variable functions. So the first function after (λsz.s(sz)) becomes s and the second function becomes z.

We plug and play and see λsz.s(sz) turn to:

λwyx.y((wy)x))(λwyx.y((wy)x))(λuv.u(u(uv)))

This is an example of one iteration of the whole function. We got rid of λs and λz by evaluating all instances of ‘s’ and ‘z’. We say that λs binds all instances of the variable ‘s’ after the argument (after the dot in λsz.s(sz)). This is true as long as the the variable ‘s’ comes after λs and before any other λ. For example, λx.y (λx.z x). The third ‘x’ is bound to the nearest λx (both in bold). So the third x evaluates to the second λx. There’s also free variable that aren’t bound to anything. For example, (λy. y) x <- here we see that the variable y, after the dot, is bound to the λy. The x, however, isn’t bound to anything. (λy.y) x is an example of a function application. More concretely, it represents the act of calling the function (λy.y) with x as an input.

Here we see how the function acts as a variable for another function in order to produce another function. This is a process called currying; it’s solving each function, one by one, by order of operation (evaluating right to left) in order to reach the normal form of the function. The normal form is when a function cannot be reduced any further. I think it gets more complicated than that because there are different types of normal form (example) and different ways to reduce. Not all functions have normal forms (it depends on whether we’re using type lambda or untype lambda; but more on that later). None of that is important for now. For more info click on the previous instance of info.

I’m not going to go too much into the parentheses and when you drop them and how you add them, but that’s not important for our evaluation at the moment. But remember that in general, “the convention is that expressions associate from the left: uvxyz, for instance, is the same as (uv)xyz, which is the same as ((uv)x)yz, (((uv)x)y)z, and finally ((((uv)x)y)z).”

Going back to the problem, we notice that the functions in bold are united with parenthesis. This means, like in other maths, that we evaluate the stuff inside the parenthesis first:

λwyx.y((wy)x))(λwyx.y((wy)x)(λuv.u(u(uv))))

These functions being evaluated leads to the λw being evaluated and replaced by the variable/function λuv.u(u(uv))

λwyx.y((wy)x)) (λwyx.y((wy)x)(λuv.u(u(uv))))

After “reducing” the function, we’re left with

λwyx.y((wy)x)) λyx.y(λuv.u(u(uv))yx)

Again, we evaluate the parentheses first and thus change the u and v with y and x and then drop the λuv

We replace, or reduce, (λwyx.y(wyx) with every instance of u and v after the dot and we remove the λuv before the dot. Thus we get:

λwyx.y((wy)x)) λyx.y(y(y(y(x))

WHAT IS THAT?! The number 4!!! Since there’s 4 y’s within the successive function

We focus back the rest of our equation:

λwyx.y((wy)x))(λyx.y(y(y(y(x)))

And we evaluate it one more time:

λyx.y(y(y(y(y(x)))))(yx)

One more time. Replace the y and x with y and x and drop the λyx. We ended up with a similar naming scheme for the variables (x and y) but we could have changed the variable names for clarity (source)

(y(y(y(y(y(x)))

And this is the same as the number 5

Thus we can see how Lambda Calculus uses functions as answers to function functions. Or worded, differently, a value in Lambda Calculus is a function

Another “confusing part of standard Lambda calculus, when first approaching it, is the fact that we do not give names to functions. Any time we want to apply a function, we write the whole function definition and then proceed to evaluate it.”

That’s why above the function was defined with the problem. λsz.s(sz) is not only the number two; the value 2 arises from how the function functions. The two are inseparable. Note again the inherent pragmatic nature of the relationship.

iii. The Fibonacci Sequence as an example of Recursion