You Can Explain Functional Programming Using Emojis

A visual representation of Lambda calculus, Church encoding, and Y combinator

Shu Uesugi (@chibicode)
You Can Explain Functional Programming Using Emojis

Last month, I published a free online course called “Y Combinator for Non-programmers”. In this 17-page course, I explain functional programming concepts such as lambda calculus, Church encoding, and Y combinator in a way such that people who have zero programming knowledge can understand.

I didn’t use any code to explain these concepts. Instead, I created something called “emoji puzzles” that can visualize functional code. In this article, I’ll explain how my emoji puzzles can represent and execute functional code visually.

Quick Demo

First, here’s simple, functional JS code. Try pressing Run below to see the result:

Functional JS code:
(sushi => sushi)('sandwich')
Press this button!

The above code can be expressed visually using my emoji puzzle below. Try pressing Run :

Equivalent emoji puzzle:
Press this button!

I’ll explain how it works shortly. If you like to teach programming, or if you like functional programming, I think you’ll enjoy this article.

Overview

This article has 10 steps:

  • In the first half (steps 1 - 5): I’ll show you how simple JavaScript code can be represented visually using my emoji puzzles. You’ll be able to understand it even if you’re not familiar with JS.
  • In the second half (steps 6 - 10): I’ll talk about how I used my emoji puzzles to explain functional programming concepts such as lambda calculus, Church encoding, and Y combinator.

Some announcements:

This article is for programmers. If you’re a non-programmer, check out my course instead: “Y Combinator for Non-programmers”.

Step 1/10 · From my course’s Beginner 3 level

Identity function in JS

Take a look at the following code. It’s an identity function in JavaScript that returns the argument.

// Identity function in JS
sushi => sushi

If you apply the above function on a string 'sandwich', the result will be 'sandwich'.

// The result will be 'sandwich'
(sushi => sushi)('sandwich')

One day, I realized that the above JS code can be described visually using emojis like below. I called this an “emoji puzzle”.

An “emoji puzzle” that visually describes
(sushi => sushi)('sandwich')

The above emoji puzzle is equivalent to the earlier JS code. First, the identity function sushi => sushi

(sushi => sushi)('sandwich')

…is represented by the bottom two items, which are both sushi .

sushi => sushi is represented
by the bottom two items

Second, the argument 'sandwich' to the identity function…

(sushi => sushi)('sandwich')

…is represented by the top item, which is a sandwich .

The argument 'sandwich' is represented
by the top item

That’s how my emoji puzzles can visually describe a simple JS expression. Next, let’s talk about how we can run it.

Note: To keep things simple, emoji puzzles don’t distinguish between variable names (e.g. sushi) and strings (e.g. 'sushi'). Therefore, both sushi and 'sushi' will be represented as .

Why emojis? I used emojis because they are not scary-looking for non-programers. I used food emojis because…I like food.


Step 2/10 · From my course’s Beginner 4 level

Running the function

I’ve added the Run button to the JS code snippet below. If you press it, you’ll see that the result is 'sandwich'.

(sushi => sushi)('sandwich')
Press this button!

We can also “run” the equivalent emoji puzzle and get the same result. Try pressing the Run button below.

An emoji puzzle that’s equivalent to
(sushi => sushi)('sandwich')
Press this button!

The result is a sandwich , which is the same as what happens when you run the equivalent JS code.

So, you can run an emoji puzzle just as you can run a piece of JS code. This is how I taught functional programming to non-programmers in my course (Y Combinator for Non-programmers)—without showing any code.

Let’s take a look at another example. Here’s a piece of JS code that’s slightly different from before. It’s a function that ignores the input and always returns 'pizza'.

// A function that ignores the input
// and always returns 'pizza'
sushi => 'pizza'

Let’s run the above code with 'sandwich' as the argument. Press Run :

(sushi => 'pizza')('sandwich')

As expected, the result is 'pizza'. Now, this code can be represented using an emoji puzzle as follows. Press Run :

An emoji puzzle that’s equivalent to
(sushi => 'pizza')('sandwich')

Just like the JS code, the emoji puzzle ended up with a pizza after running it.

What we have learned so far: Simple JS code like below can be represented using emoji puzzles.

Functional JS code:
(sushi => sushi)('sandwich')
Result: 'sandwich'
Equivalent emoji puzzle:

Functional JS code:
(sushi => 'pizza')('sandwich')
Result: 'pizza'
Equivalent emoji puzzle:

Step 3/10 · From my course’s Beginner 4 level

Visualizing evaluation rules

If you know how to code, you have a mental model of how function evaluation works:

  • If you see (sushi => sushi)('sandwich'), you can quickly figure out that the result would be 'sandwich'.
  • If you see (sushi => 'pizza')('sandwich'), you know that the result would be 'pizza'.
  • You know what free variables and bound variables mean.

On the other hand, most non-programmers don’t have a mental model of how function evaluation works. To help them develop the mental model, I created a step-by-step visualization of function evaluation rules using emoji puzzles.

Let’s reuse the earlier example again:

Functional JS code:
(sushi => sushi)('sandwich')
Equivalent emoji puzzle:

On the puzzle below, try pressing the Run button. This button is a bit different from the last time—it shows every step that happens in between.

Press this button!

Here are the four steps it displayed:

Step 1. Label: t l r

First, we label each emoji. The top item is labeled as t (for “Top”), the left item is labeled as l (for “Left”), and the right item is labeled as r (for “Right”).

Label: t l r
tlr

Step 2. Match: l r

Second, we check to see if some of l’s and r’s match. If they match, add the sign. In this case, both the bottom-left and the bottom-right are sushi , so there’s a match.

Match: l r
tlr

Step 3. Copy: t r

Third, we copy t’s to where the matched r’s are. In this case, we copy the sandwich on the top to the bottom-right.

Copy: t r
tlr

Step 4. Remove: t l

Finally, we remove t’s and l’s. We’re left with just the sandwich at the end.

Remove: t l
tl

The above steps are a visual representation of how functions are evaluated. They are equivalent to how JavaScript evaluates (sushi => sushi)('sandwich').

By learning these rules, non-programmers will be able to evaluate functions intuitively.

Note: The above steps would look very confusing to most programmers. As programmers, we already know how to evaluate functional expressions, and we instinctively try to map the above diagrams to code in our head.

But in my testing, it seems to be less confusing to non-programmers who don’t already have a mental model of function evaluation. Furthermore, in the course itself, I slow down and spend a lot more time covering the above rules—the explanations are spread out in a full page (here). And I don’t show any code in my course—I only show emoji puzzles, so one less source of confusion compared to this article.

One thing I learned is that the feedback on my course from programmers and non-programmers are complete opposites—generally negative from programmers but generally positive from non-programmers. I believe that’s because many programmers find that using code is simpler than using the above diagrams, but many non-programmers think the opposite.

Some people have incredible difficulty understanding code or math symbols, and sometimes visual alternatives help them. I believe the more alternative teaching methods are offered in CS education, the better.


Step 4/10 · From my course’s Beginner 4 level

If there’s no match

Let’s take a look at the other example from earlier:

Functional JS code:
(sushi => 'pizza')('sandwich')
Equivalent emoji puzzle:

Try pressing the Run button and see what happens:

Here are the three steps it displayed:

Step 1. Label: t l r—this is the same as before.

Label: t l r
tlr

Step 2. This time, there’s no match between l and r. The bottom-left is sushi , but the bottom-right is pizza .

No match: l r
tlr

If there’s no match, we skip step 3 (Copy: t r) and go directly to step 4.

Step 4. Remove: t l

tl

So we’re left with a pizza . That’s how the emoji puzzle visualizes the evaluation of a function when there’s no matching variable in the function body.

More examples (optional read): Here are more examples that might be helpful for your understanding. You can press Run on each example to see the evaluation visualization. (Or press to step through manually.)

Functional JS code:
(pizza => pizza)(spaghetti => 'bread')
Result: (spaghetti => 'bread')
Equivalent emoji puzzle:

Functional JS code:
(salad => 'hotDog')(curry => 'tacos')
Result: 'hotDog'
Equivalent emoji puzzle:

Step 5/10 · From my course’s Beginner 5 level

More complicated expressions

Let’s take a look at more complicated functional JS expressions and see if they can be represented using an emoji puzzle.

Check out the following JS expression, and try to guess what the result would be before pressing the Run button.

Guess what the result would be
before pressing the Run button.
(sushi => sandwich => sushi)(
'hamburger'
)('chicken')

The result was 'hamburger'. It’s because:

  • sushi is bound to 'hamburger',
  • sandwich is bound to 'chicken',
  • And it returns the value of sushi, which is 'hamburger'.

Now, here’s the equivalent emoji puzzle:

2
1
12

Let’s break it down. First, the function expression…

(sushi => sandwich => sushi)(
'hamburger'
)('chicken')

…is represented by the bottom row:

sushi => sandwich => sushi
2
1
12

And the two arguments…

(sushi => sandwich => sushi)(
'hamburger'
)('chicken')

…are represented by the top and the middle rows:

('hamburger')('chicken')
2
1
12

How do we evaluate this function? Well, in JS, we first evaluate the function call with the argument 'hamburger'.

In JS, we evaluate this part first
(sushi => sandwich => sushi)(
'hamburger'
)('chicken')

Equivalently, in an emoji puzzle, we evaluate the bottom two rows first. We ignore the top row initially, which is shaded in blue.

Focus on the bottom two rows, and
Ignore the top row for now
2
1
12

Also, if you look at the left edge of the puzzle above, the bottom two rows correspond to the pair of 1’s. That’s how you know that you must start with the bottom two rows. In an emoji puzzle with 3 rows, you start with the pair of 1’s.

Next, let’s label each item on the bottom two rows. This time, in addition to t l r, we now have a new label m for the sandwich .

There’s a new label m
for the sandwich
2
1
t
l
12
m
r

Here’s the rule: The middle item on the bottom row is labeled as m (for “Middle”), and you can ignore it. You can pretend that m’s don’t exist.

Let’s take a look at the next few steps in this iteration, which is just like what we saw earlier:

There’s a match among l’s and r’s
2
1
t
l
12
m
r
Copy t’s to where the matched r’s are
2
1
t
l
12
m
r
Remove t’s and l’s
2
1
t
l
12
1
1

This is exactly like how the earlier JS code is evaluated.

After evaluating this part…
(sushi => sandwich => sushi)(
'hamburger'
)('chicken')
…it becomes this, which is
equivalent to the above emoji puzzle
(but it’s not done yet!)
(sandwich => 'hamburger')('chicken')

But we’re not done yet! Let’s continue to the end by pressing the Run button below:

Let’s continue to the end!
1
1

We ended up with a hamburger , which is exactly the same as what the JS code evaluated to.

What we have learned so far: Complex functional JS expressions can be represented and evaluated using an emoji puzzle.

Functional JS code:
(sushi => sandwich => sushi)(
'hamburger'
)('chicken')
Result: 'hamburger'
Equivalent emoji puzzle:
(Start with the pair of 1’s)
2
1
12

More examples (optional read): Here’s another example that might be helpful for your understanding. Check out the following JS expression, and try to guess what the result would be before pressing the Run button.

Guess what the result would be
before pressing the Run button.
(friedPotatoes => pizza => pizza)(
spaghetti => spaghetti
)('salad')

The result was 'salad'. Now, here’s the equivalent emoji puzzle below. Try pressing Run . Again, remember that:

  • We start with the pair of 1’s.
  • The middle item on the bottom row is labeled as m, and you can ignore it.
Equivalent emoji puzzle:
2
1
12

Next, here’s slightly different JS code. Compared to the last time, there’s an extra pair of parentheses around (spaghetti => spaghetti)('salad'), which changes the result.

Guess what the result would be
before pressing the Run button.
// There’s an extra pair of parens around
// (spaghetti => spaghetti)("salad")
(friedPotatoes => pizza => pizza)(
(spaghetti => spaghetti)("salad")
)

Let’s take a look at the equivalent emoji puzzle. This time, the pair of 1’s is on the top two rows instead. So we start with the top two rows this time. Try pressing Run and see what happens.

This time, the pair of 1’s is
on the top two rows instead
12
1
2

Summary:

  • In JavaScript, you can change the evaluation order of an expression by placing parentheses on different locations.
  • In emoji puzzles, you can change the evaluation order by placing the numbers (e.g. 1’s and 2’s) on different locations.

Step 6/10 · From my course’s Intermediate 1 level

Church numerals

You’re halfway there: 5 steps down, 5 more to go!

If you’re thinking of taking a break, I’d appreciate it if you could Share this article on Twitter before you close this page.

From now on, we’ll apply what we’ve learned so far to solve more interesting problems.

Here’s a function called convert that takes a function f as an argument. It then calls f with (n => n + 1)(0).

function convert(f) {
return f(n => n + 1)(0)
}

Now, suppose that we apply convert on this function: sushi => sandwich => sandwich. What would the result be? Try to guess before pressing the Run button.

Guess what the result would be
before pressing the Run button.
function convert(f) {
return f(n => n + 1)(0)
}
convert(sushi => sandwich =>
sandwich
)

The result is 0 because:

  • sushi is bound to n => n + 1
  • sandwich is bound to 0
  • And it returns sandwich, which is 0.

Next: What if the input to convert changes as follows? Try pressing Run on each example.

convert(sushi => sandwich =>
sushi(sandwich)
)
convert(sushi => sandwich =>
sushi(sushi(sandwich))
)
convert(sushi => sandwich =>
sushi(sushi(sushi(sandwich)))
)

The results are 1, 2, and 3 respectively because:

  • sushi is bound to n => n + 1
  • sandwich is bound to 0
  • So it applies n => n + 1 to 0 for the number of times sushi is used in the function body.

What we have learned so far: If we have a function that has one of the following patterns:

// a & b can be any variable name
a => b => b
a => b => a(b)
a => b => a(a(b))
a => b => a(a(a(b)))
// ...and so on...

Then, when the function is passed to convert(), it returns the number of times a is applied to b in the function body.

convert(a => b => b) // 0
convert(a => b => a(b)) // 1
convert(a => b => a(a(b))) // 2
convert(a => b => a(a(a(b)))) // 3
// ...and so on...

Important: These functions that can be converted to a number using convert() have a special name. They are called Church numerals. Each function represents a Church numeral, like this:

// Church numeral 0
a => b => b
// Church numeral 1
a => b => a(b)
// Church numeral 2
a => b => a(a(b)))
// Church numeral 3
a => b => a(a(a(b))))
// ...and so on...

You might be wondering: “What’s the point of this?” Don’t worry—I’ll tell you why Church numerals are interesting shortly. But before I do, let me explain how emoji puzzles can express Church numerals.

Here’s an emoji puzzle that represents sushi => sandwich => sandwich, which is Church numeral 0.

Represents:
sushi => sandwich => sandwich
(Church numeral 0)

Here’s what’s new: We now have the “Convert to a Number” button below the puzzle which converts it to the corresponding Church number. Try pressing it:

Press this button!

Other Church numeral functions can also be represented using emoji puzzles, and they can be converted to a number. And we can use emojis other than and —as long as they follow the same pattern.

Represents:
hamburger => chicken => hamburger(chicken)
(Church numeral 1)
1
1
Church numeral 2
12
1
2
Church numeral 3
123
1
2
3

Now that we’ve covered the basics of Church numerals, we’ll talk next about why Church numerals are interesting.


Step 7/10 · From my course’s Intermediate 3 level

Arithmetic with functions

Church numerals are interesting because they let you do arithmetic with functions. Take a look at this function:

sushi => sandwich => pizza =>
sandwich(
sushi(sandwich)(pizza)
)

It looks pretty complicated, but don’t worry too much. Now, suppose that:

  • We apply the above function to the Church numeral zero (has the pattern a => b => b), and
  • Run convert() (from earlier) on it.
  • What would the result be?

Let’s take a look. Try to guess before pressing the Run button.

// Function from the above
const f = sushi => sandwich => pizza =>
sandwich(
sushi(sandwich)(pizza)
)
// Church numeral zero
const zero = chicken => salad => salad
// What happens when you apply f to zero,
// and convert it?
convert(f(zero))

The result is 1, which is 1 greater than the input Church numeral, which was 0. In other words, 0 became 1.

0 became 1

Here’s the secret: This function f we used actually adds 1 to the input Church numeral. When you apply f to a Church numeral, it returns a new Church numeral that’s 1 greater than before.

// If we apply this function to a
// Church numeral, it returns a new
// Church numeral that’s greater by 1.
const f = sushi => sandwich => pizza =>
sandwich(
sushi(sandwich)(pizza)
)

You can try out more examples to verify this:

// Church numeral one
const one = chicken => salad =>
chicken(salad)
convert(f(one))
// Church numeral two
const two = chicken => salad =>
chicken(chicken(salad))
convert(f(two))

This is what I mean by “doing arithmetic with functions”:

  • By using a Church numeral function that can be converted to someNumber
  • …and the function f we saw earlier,
  • You can calculate someNumber + 1.
You can calculate someNumber + 1
using just functions

Now, let’s see if we can explain this to non-programmers using emoji puzzles.

First, here’s an emoji puzzle representation of the Church numeral 0. You can confirm that it can be converted to by pressing the button below.

Represents:
chicken => salad => salad
(Church numeral 0)

And here’s the function f we saw earlier, represented as an emoji puzzle:

const f = sushi => sandwich => pizza =>
sandwich(
sushi(sandwich)(pizza)
)
Equivalent emoji puzzle:
23
1
12
3

Let’s apply f to the Church numeral 0. To do that, we just combine the above two emoji puzzles and run it. Press Run :

Combined the above two emoji puzzles
1
1
23
1
12
3

The result is equivalent to sandwich => pizza => sandwich(pizza), which is Church numeral 1.

Represents:
sandwich => pizza => sandwich(pizza)
(Church numeral 1)
1
1

What just happened: An emoji puzzle that can be converted to became a puzzle that can be converted to .

1
Emoji puzzle that can be converted to
1
23
1
12
3
Emoji puzzle that can be converted to

In other words: We can use an emoji puzzle to calculate someNumber + 1.

More examples (optional read): Let’s see if we can calculate 1 + 1 = 2 using the same method. Here’s an emoji puzzle that can be converted to :

Represents:
chicken => salad => chicken(salad)
(Church numeral 1)
1
1

And let’s combine it with the earlier emoji puzzle and run it. Press Run :

1
1
1
1
23
1
12
3

The result is equivalent to Church numeral 2 and can be converted to .

Church numeral 2
12
1
2

So, it successfully calculated 1 + 1 = 2. Again, this is what just happened:

1
Emoji puzzle that can be converted to
1
23
1
12
3
Emoji puzzle that can be converted to

Step 8/10 · From my course’s Advanced 5 level

Multiplications

You can do pretty much any computation with Church numerals. Consider multiplication. Here’s a JS function that multiplies two Church numerals:

// Multiplies two Church numerals
const mul = sushi => sandwich => pizza =>
sushi(sandwich(pizza))

Let’s compute 2 x 3 using the above mul function. We use two Church numeral functions—one for 2 and the other for 3, and feed them into mul. Take a look at the code below and press Run :

// Church numeral two
const two = chicken => salad =>
chicken(chicken(salad))
// Church numeral three
const three = curry => hamburger =>
curry(curry(curry(hamburger)))
const result = mul(two)(three)
convert(result)

The result was 6, so it successfully calculated 2 x 3.

Now, let’s see if we can do the same using emoji puzzles. First, here’s an emoji puzzle that’s equivalent to the mul function.

// Multiplies two Church numerals
const mul = sushi => sandwich => pizza =>
sushi(sandwich(pizza))
Equivalent emoji puzzle:
12
1
2

Let’s combine it with emoji puzzles that can be converted to and :

Converts to
12
1
2
Converts to
123
1
2
3

Here’s the combined puzzle. Press Run and see what happens. (Because it takes time, we’ll fast-forward it at 4x speed.)

2
12
1
2
1
123
1
2
3
12
12
1
2

The result is equivalent to Church numeral 6 and can be converted to .

Church numeral 6
123456
1
2
3
4
5
6

So emoji puzzles can calculate multiplications too. In my course, I also show how we can do subtractions using emoji puzzles. Divisions are very complicated but possible.


Step 9/10 · From my course’s Advanced 2 level

Conditionals

In addition to arithmetic, we can also implement conditionals such as if/else statements using emoji puzzles.

Consider the following JS code. This is a simple if/else statement that does different things based on what x is.

if (x === 0) {
// is Zero
} else {
// is NOT Zero
}

It turns out that if/else statements like the above can also be expressed using Church numerals. To save time, I won’t show JS code this time and will only show the emoji puzzle. Check out the following:

An emoji puzzle that represents
if (x === 0) { ... } else { ... }
4