Commit e605f60a authored by Leon Byford's avatar Leon Byford

cons pairs + list post

parent c242d4dc
......@@ -36,6 +36,7 @@ We then determine which pattern the list matches against. If both items in the l
> (int->fb 64)
64
```
{:.console}
It works! Now we need to find a way to create a list of the first n numbers. We can define a function `fizzbuzz` that does this:
......@@ -60,6 +61,7 @@ Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58
Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz
97 98 Fizz Buzz)
```
{:.console}
### Bonus: FizzBuzz in ECMAScript using "pattern matching"
......@@ -94,3 +96,4 @@ Okay, so ECMAScript doesn't really have an equivalent to Racket's `match` constr
"Fizz",79,"Buzz","Fizz",82,83,"Fizz","Buzz",86,"Fizz",88,89,"FizzBuzz",91,92,
"Fizz",94,"Buzz","Fizz",97,98,"Fizz","Buzz"]
```
{:.console}
......@@ -35,6 +35,7 @@ Actually, this works exactly the same way when doing functional programming. For
> f(-2)
-1
```
{:.console}
Defining this function is different from how we do it in maths, but it's relatively intuitive:
......@@ -68,6 +69,7 @@ So now we can call the function like so:
> (f -2)
-1
```
{:.console}
And that's functional programming in a nutshell! That wasn't so bad, was it? Now, let's solve some of the problems given on the BBC Bitesize page using Racket:
......@@ -80,13 +82,16 @@ Find f(-2) and g(3)
(define (g x)
(- (expt x 2) 1))
```
```racket
> (f -2)
-4
> (g 3)
8
```
{:.console}
> f(x) = 2x + 3 and g(x) = x<sup>2</sup>
Find fg(4), gf(4) and ff(4)
......@@ -97,7 +102,9 @@ Find fg(4), gf(4) and ff(4)
(define (g x)
(expt x 2))
```
```racket
> (f (g 4))
35
......@@ -107,5 +114,6 @@ Find fg(4), gf(4) and ff(4)
> (f (f 4))
25
```
{:.console}
Piece of cake. :-)
---
layout: post
title: Cons pairs and lists in ECMAScript using Church encoding
tags: [programming]
excerpt_separator: <!-- more -->
---
One of the really cool things covered by Abelson and Sussman's classic series of lectures, [*Structure and Interpretation of Computer Programs* (SICP)](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/), was how fundamental programming constructs could be implemented almost from nothing. This, of course, culminated in the implementation of Scheme within Scheme itself, but it's interesting to look at some of the smaller building blocks.
<!-- more -->
A lot of this relies on [Church encoding](https://en.wikipedia.org/wiki/Church_encoding), with which we can implement one of the most fundamental data structures -- the cons pair:
> cons = λx . λy . λz . z x y
car = λz . z (λx . λy . x)
cdr = λz . z (λx . λy . y)
SICP explains how to implement this in Scheme, but ECMAScript (a.k.a JavaScript) is a Lisp (okay, this meme is getting old now), so it's a straightforward translation:
```js
const cons = (x, y) => z => z(x, y);
const car = z => z((x, y) => x);
const cdr = z => z((x, y) => y);
```
Cool, now we can do fun stuff like:
```js
> car(cons("hello", "world"));
"hello"
> cdr(cons("hello", "world"));
"world"
```
{:.console}
Now, how about lists? Well, we need to implement booleans first:
```js
const myTrue = (x, y) => x;
const myFalse = (x, y) => y;
const isFalse = l => l(_ => myFalse, myTrue);
```
`true` and `false` are reserved words in ECMAScript, so I have had to make up my own names for them. And now finally I can create lists by doing something like this:
```js
const list = (...args) => args.reduceRight((x, y) => cons(y, x), myFalse);
```
As you can see, lists are terminated with a `myFalse`. Implementing this without relying on ECMAScript's built-in methods are left as an exercise to the reader.
Let's try creating a list and accessing its members:
```js
> const myList = list(1, 2, 3);
function cons()
> car(myList);
1
> car(cdr(myList));
2
> car(cdr(cdr(myList)));
3
```
{:.console}
And if we want to turn that list back into an ECMAScript-native array? We can implement a function to do that:
```js
const listToArray = (thisList, thisArray=[]) => {
thisArray.push(car(thisList));
if (isFalse(cdr(thisList)) == myTrue) {
return thisArray;}
return listToArray(cdr(thisList), thisArray);}
```
And call it like so:
```js
> const foo = list("s", "u", "c", "c", "e", "s", "s");
undefined
> listToArray(foo);
[ "s", "u", "c", "c", "e", "s", "s" ]
```
{:.console}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment