56490526347a

Merge.
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Sat, 30 Mar 2013 14:10:03 -0400
parents c61d33798740 (diff) a30885eba5d3 (current diff)
children 3b0fb0a3ea52
branches/tags (none)
files

Changes

--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/blog/2013/03/list-out-of-lambda.html	Sat Mar 30 14:10:03 2013 -0400
@@ -0,0 +1,1066 @@
+    {% extends "_post.html" %}
+
+    {% hyde
+        title: "List Out of Lambda"
+        snip: "Down the rabbit hole we go!"
+        created: 2013-03-30 14:00:00
+        flattr: true
+    %}
+
+    {% block article %}
+
+If you ignore the practical issues of computers like size, weight, cost, heat,
+and so on, what do you *really* need in a programming language?  Let's play
+around with this question.
+
+To understand this post you'll need a basic understanding of how functions in
+Javascript work.  If you can look at this code and understand what it prints,
+you're good to go:
+
+    :::javascript
+    var x = 10;
+
+    var f = function(y) {
+        console.log(x);
+        console.log(y);
+    }
+
+    var g = f;
+
+    f(1);
+    g(2);
+
+This blog post is a thought exercise.  It's not something you'd ever use for
+real code.  But just like a guitarist practices scales that she won't ever play
+in a song, we programmers should be exercising our brains every so often.
+
+I'm going to use Javascript for the examples.  Any language with first class
+functions and lexical scoping (basically: closures) will work.  The examples
+would be prettier in a Lisp, but some people would be turned off by the syntax
+and miss out on some interesting ideas.  Feel free to port the code if it
+bothers you.
+
+If you've already seen this kind of thing before (maybe you've gone through [The
+Little Schemer][] or [SICP][]) you may want to just skim the code here and look
+for anything new.
+
+If you *haven't* seen anything like this, then you're in for a treat!  It's all
+going to look extremely weird the first time you see it.  Go slowly and make
+sure you understand each piece fully before moving on to the next.  These
+concepts may be unintuitive, but they're built from very simple pieces.
+
+Finally: if you get stuck, don't worry.  Tracing out the execution of a function
+on paper can be a good way to wrap your brain around it (I recommend investing
+in a good lap desk for comfy reading and writing).  If that doesn't work, just
+close the window and come back tomorrow.  Sometimes new concepts need a while to
+rattle around in your brain before they click into place.
+
+[The Little Schemer]: http://www.amazon.com/dp/0262560992/?tag=stelos-20
+[SICP]: http://www.amazon.com/dp/0070004846/?tag=stelos-20
+
+[TOC]
+
+Lists
+-----
+
+Let's get started.  One of the most common things we do as programmers is
+grouping data together.  Javascript has "arrays" built in to the language for
+this:
+
+    :::javascript
+    var names = ["Alice", "Bob", "Candice"];
+
+What if Javascript didn't come with arrays included?  Could we create them (or
+something like them) ourselves?
+
+To answer this, let's think about the bare minimum we'd need to "bootstrap"
+something like an array.  There are a number of ways to do this, but we're going
+to look at one in particular.
+
+We'll call our array-like thing a "list".  To make it work, we need four parts:
+
+* The concept of "the empty list".
+* A way to add an element to the front of a list.
+* A way to take a list and get the first element.
+* A way to take a list and get everything *but* the first element.
+
+If we have those four things, we can build on top of them to do anything else we
+might want.  For example: to make a list of one item, you add that item to the
+front of the empty list.
+
+Let's narrow this down further.  There are lots of ways you could implement
+those four things -- I'm going to use functions.  Let's sketch out an outline:
+
+    :::javascript
+    var empty_list = null;
+
+    var prepend = function(el, list) {
+        // ...
+    };
+
+    var head = function(list) {
+        // ...
+    };
+
+    var tail = function(list) {
+        // ...
+    };
+
+    var is_empty = function(list) {
+        // ...
+    };
+
+Here are the descriptions of each of these items.
+
+The `empty_list` is a special value that represents a list of zero elements.
+It can be anything, so for now we'll use `null` (we'll revisit this later).
+
+`prepend(1, some_list)` will return a new list that looks like the old one, but
+with `1` stuck onto the front of it.  So if we want to create a list of the
+numbers `1` and `2` we can say `prepend(1, prepend(2, empty_list))` or "prepend
+one to the result of prepending 2 to the empty list".
+
+`head(some_list)` will return the first element in the list.  Calling it on the
+empty list will be undefined, so we'll just be very careful not to do that!
+
+`tail(some_list)` will return a new list that's like the one we gave it, but
+with the first element removed.  Again, calling this on an empty list will make
+things explode.
+
+`is_empty(some_list)` will return `true` if the list given to it is the empty
+list, and `false` otherwise.
+
+Once we have those four functions (plus the special empty list value) we can
+start building on top of them, so let's figure out how to make them!
+
+### List Out of If
+
+If you haven't seen anything like this before, you might think it's time to
+start creating Javascript Objects.  That's certainly one way to do it.
+
+Since this post is a thought experiment in what we actually *need*, though,
+let's try to avoid using big language features (like Objects) unless we
+absolutely can't avoid it.
+
+So if we don't want to use other language features yet, what are we left with?
+Well so far our skeleton only has functions (and `null`), so let's try those!
+
+Here's the first working revision of the building blocks of lists:
+
+    :::javascript
+    var empty_list = null;
+
+    var prepend = function(el, list) {
+        return function(command) {
+            if (command === "head") {
+                return el;
+            } else if (command === "tail") {
+                return list;
+            }
+        }
+    };
+
+    var head = function(list) {
+        return list("head");
+    };
+
+    var tail = function(list) {
+        return list("tail");
+    };
+
+    var is_empty = function(list) {
+        return list === null;
+    };
+
+Go ahead and paste that into a browser console and play with it:
+
+    :::javascript
+    var e = empty_list;
+
+    console.log(is_empty(e));
+    // true
+
+    var names = prepend("Alice",
+                        prepend("Bob",
+                                prepend("Candice",
+                                        empty_list)));
+
+    console.log(is_empty(names));
+    // False
+
+    console.log(head(names));
+    // Alice
+
+    console.log(tail(names));
+    // Some function representing the list of ("Bob", "Candice")
+
+    console.log(head(tail(names)));
+    // Bob
+
+### But Where is the Data?
+
+Did the definitions of those functions surprise you?  Lists seem like such an
+important, object-oriented concept, but there only appear to be functions here!
+
+Let's look at how this actually works.  First of all, the "empty list" concept
+is pretty straightforward:
+
+    :::javascript
+    var empty_list = null;
+
+    var is_empty = function(list) {
+        return list === null;
+    };
+
+We could have picked any arbitrary value here.  `null` seemed appropriate, so
+I used that.
+
+Now on to the meat of things: `prepend`.
+
+    :::javascript
+    var prepend = function(el, list) {
+        return function(command) {
+            if (command === "head") {
+                return el;
+            } else if (command === "tail") {
+                return list;
+            }
+        }
+    };
+
+This is where the real magic happens.  Let's think through it.
+
+First of all, we know that when you prepend something to a list, you're going to
+get a (new) list back.  So whatever `prepend` returns must be a list.
+
+Looking at the code, we can see it returns a function.  So in our little thought
+experiment, a list is actually a Javascript function under the hood!
+
+So what do we need to do with lists (aside from empty checking, which we've
+already covered)?  Well, we need to be able to get the head and the tail.  When
+we call `prepend(h, t)`, we happen to be conveniently specifying the head and
+tail as the arguments!  So in `prepend` we return a function that knows how to
+return its own head or tail when asked.
+
+So a "list" is "a function that knows how to return its own head or tail when
+asked".  So our `head` and `tail` functions just need to ask nicely!
+
+    :::javascript
+    var head = function(list) {
+        return list("head");
+    };
+
+    var tail = function(list) {
+        return list("tail");
+    };
+
+That's it!  We've created lists in 23 lines of code without using any fancy
+things like Objects.  Before you move on, make sure you really understand why
+this works.  Write out a few examples on paper.
+
+    :::javascript
+    var empty_list = null;
+
+    var prepend = function(el, list) {
+        return function(command) {
+            if (command === "head") {
+                return el;
+            } else if (command === "tail") {
+                return list;
+            }
+        }
+    };
+
+    var head = function(list) {
+        return list("head");
+    };
+
+    var tail = function(list) {
+        return list("tail");
+    };
+
+    var is_empty = function(list) {
+        return list === null;
+    };
+
+### Building on the Foundations
+
+Now that we have lists, let's implement a few common things on top of them as
+practice.
+
+#### map
+
+A common thing to do to a list is to create a new list by looping through it and
+doing something to each item.  This is called "map":
+
+    :::javascript
+    var map = function(fn, l) {
+        if (is_empty(l)) {
+            return empty_list;
+        } else {
+            return prepend(fn(head(l)), map(fn, tail(l)));
+        }
+    };
+
+If you're not used to recursive definitions like this, you may way to take
+a few minutes and try to work out how it works.  Here's an example:
+
+    :::javascript
+    var square = function(x) {
+        return x * x;
+    }
+    var numbers = prepend(1, prepend(2, prepend(3, empty_list)));
+
+    var squared_numbers = map(square, numbers);
+    // map(square, [1, 2, 3])
+    // prepend(square(1), map(square, [1, 2, 3]))
+    // prepend(square(1), prepend(square(2), map(square, [3])))
+    // prepend(square(1), prepend(square(2), prepend(square(3), map(square, []))))
+    // prepend(square(1), prepend(square(2), prepend(square(3), [])))
+    // prepend(square(1), prepend(square(2), prepend(9, [])))
+    // prepend(square(1), prepend(square(2), [9]))
+    // prepend(square(1), prepend(4, [9]))
+    // prepend(square(1), [4, 9])
+    // prepend(1, [4, 9])
+    // [1, 4, 9]
+
+I'm using brackets here to represent lists, but remember that these aren't
+arrays, but are actually the functions that were returned by `prepend`.
+
+If you're still not sure about this, trace out every step of `map(square,
+empty_list)` on paper.  Then trace out every step of `map(square, prepend(10,
+empty_list))`.
+
+Thinking recursively like this takes some practice.  I have notebooks filled
+with [pages like this](http://i.imgur.com/kqu5jy9.jpg).  Experienced guitarists
+practice new material slowly and methodically -- there's no reason programmers
+shouldn't do the same.  Watching the function calls expand and contract on paper
+can help you feel in your gut how these things work in a way that just staring
+at the words can't.
+
+#### filter
+
+We're going to start moving a bit faster now, but you should still make sure you
+understand everything completely before moving on.  Take as much time as you
+need.  Write things out.  Run them.  Get a feel for them.
+
+The next "utility" function we'll build on top of lists is `filter`, which
+takes a function and a list, and returns a new list whose elements are those in
+the original that make the function return `true`.  Here's an example:
+
+    :::javascript
+    var numbers = prepend(1, prepend(2, prepend(3, empty_list)));
+    var is_odd = function(x) {
+        return x % 2 === 1;
+    }
+
+    filter(is_odd, numbers);
+    // [1, 3]
+
+Now let's implement `filter`:
+
+    :::javascript
+    var filter = function(fn, l) {
+        if (is_empty(l)) {
+            return empty_list;
+        } else if (fn(head(l))) {
+            return prepend(head(l), filter(fn, tail(l)));
+        } else {
+            return filter(fn, tail(l));
+        }
+    };
+
+Take your time.  Trace out some examples.  Move on when you feel it in your gut.
+
+#### and, or, not
+
+Let's take a slight detour to implement a few "helper" functions.  Ī¤hese don't
+have anything specifically to do with lists, but we'll need them later.
+
+    :::javascript
+    var not = function(x) {
+        if (x) {
+            return false;
+        } else {
+            return true;
+        }
+    };
+
+    var and = function(a, b) {
+        if (a) {
+            if (b) {
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    };
+
+    var or = function(a, b) {
+        if (a) {
+            return true;
+        } else {
+            if (b) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+    };
+
+Javascript already has these things built in as `!`, `&&`, and `||`, of course,
+but remember that in this thought exercise we're trying to avoid using extra
+language features if we don't need them.  How far can we scrape by on just
+functions and `if` statements?
+
+One small note: these functions are just normal Javascript functions, which
+means that `and(a, b)` will *not* short-circuit like `a && b` would.  For our
+purposes here that won't hurt us, but it's something to be aware of.
+
+### List Out of Lambda
+
+Now that we've had a bit more practice, let's go back to our definition of
+lists:
+
+    :::javascript
+    var empty_list = null;
+
+    var prepend = function(el, list) {
+        return function(command) {
+            if (command === "head") {
+                return el;
+            } else if (command === "tail") {
+                return list;
+            }
+        }
+    };
+
+    var head = function(list) {
+        return list("head");
+    };
+
+    var tail = function(list) {
+        return list("tail");
+    };
+
+    var is_empty = function(list) {
+        return list === null;
+    };
+
+There are a few things about this implementation that bother me.  Our goal is to
+use as few language features as possible, but we've actually used quite a few!
+I count at least five:
+
+* Functions
+* `if` statements
+* Strings
+* Booleans (the `true`/`false` result of `is_empty`)
+* Equality checking (the `===` checks)
+
+It turns out we can remove most of those things at the cost of a bit of
+readability (and more bending of our minds).
+
+Let's start by rewriting the core three functions to ditch those ugly strings,
+equality checks, and even the `if` statement:
+
+    :::javascript
+    var prepend = function(el, list) {
+        return function(selector) {
+            return selector(el, list);
+        };
+    };
+
+    var head = function(list) {
+        return list(function(h, t) {
+            return h;
+        });
+    };
+
+    var tail = function(list) {
+        return list(function(h, t) {
+            return t;
+        });
+    };
+
+You may want to get a snack before wrapping your brain around this one!  There's
+no strings, no equality checking, no `if` statements.  But we still have lists!
+
+The `prepend` functions still returns a function, just like before.  Remember
+that in the last implementation, a "list" was really a function that knew how to
+give out its head or its tail when asked for them.
+
+This time, we're inverting the "asking".  In this version, a "list" is "a
+function that will tell another function about both its head *and* its tail when
+asked".  This time the *asker* gets *both* pieces, and can decide which one they
+want to use.
+
+Let's look at the `head` function:
+
+* `head` takes a list and says `return list(...)`, which means: "Hey list,
+  I would like you to tell all of your info to this little helper function I'm
+  giving you".
+* The list says `return ...(el, list)`, which means: "Okay helper function,
+  here's my head and my tail, enjoy!"
+* The helper function that `head` originally gave was `function(h, t) { return
+  h; }`.  So when the list calls it with the head and the tail as arguments, it
+  returns the head and ignores the tail.
+* `head` takes that result and just returns it straight through back to the
+  caller.
+
+`tail` works exactly the same way, but its helper function returns the second
+argument (the tail) instead of the first.
+
+That's it!  The equality checking and `if` statements have disappeared.  Can you
+describe where they've gone?  What has taken their place?
+
+Before we move on, let's clean up the idea of the empty list.  It's still using
+`null` and equality checking.  Let's remove those and make things a little more
+uniform.
+
+To do this we'll need to change the other three functions a bit as well, but if
+you've understood everything so far it shouldn't be too bad.
+
+    :::javascript
+    var empty_list = function(selector) {
+        return selector(undefined, undefined, true);
+    };
+
+    var prepend = function(el, list) {
+        return function(selector) {
+            return selector(el, list, false);
+        };
+    };
+
+    var head = function(list) {
+        return list(function(h, t, e) {
+            return h;
+        });
+    };
+
+    var tail = function(list) {
+        return list(function(h, t, e) {
+            return t;
+        });
+    };
+
+    var is_empty = function(list) {
+        return list(function(h, t, e) {
+            return e;
+        });
+    };
+
+We've now made lists a bit smarter.  In addition to telling the helper function
+their head and tail, they also tell it "am I the empty list?".  We've modified
+the helpers `head` and `tail` to accept (and ignore) this extra argument.
+
+We then modified `is_empty` to work just like `head` and `tail`.
+
+Finally, we've redefined `empty_list` to match the rest of the lists instead of
+being a special, magic value.  The empty list is now just like a normal one:
+it's a function that takes an "asker" and tells that asker "Hey, my head and
+tail are undefined and I am the empty list".
+
+I used `undefined` here which is technically another language feature because
+it's easier to read.  Feel free to replace it with anything you want to make it
+more pure.  Since we're being very careful to never call `head` or `tail` on the
+empty list those values will never be seen anyway.
+
+So after all that, we've finally implemented the building blocks of lists with
+only two things:
+
+* Functions.
+* `true` and `false` for empty lists.
+
+If you're up for a challenge, think about whether you could remove that second
+item (and if so, are you *really* removing it, or just using certain features of
+Javascript implicitly instead of explicitly?).
+
+A Brief Intermission
+--------------------
+
+Let's take a minute to reflect on all the code we've seen so far.  First, we
+have an implementation of lists that uses only functions and booleans:
+
+    :::javascript
+    var empty_list = function(selector) {
+        return selector(undefined, undefined, true);
+    };
+
+    var prepend = function(el, list) {
+        return function(selector) {
+            return selector(el, list, false);
+        };
+    };
+
+    var head = function(list) {
+        return list(function(h, t, e) {
+            return h;
+        });
+    };
+
+    var tail = function(list) {
+        return list(function(h, t, e) {
+            return t;
+        });
+    };
+
+    var is_empty = function(list) {
+        return list(function(h, t, e) {
+            return e;
+        });
+    };
+
+From this point on, we can now ignore the details of how lists are implemented.
+As long as we have `head`, `tail`, and `prepend` we don't need to worry about
+what lists actually *are* under the hood.
+
+We also built a few helper functions on top of this foundation:
+
+    :::javascript
+    var not = function(x) {
+        if (x) {
+            return false;
+        } else {
+            return true;
+        }
+    };
+
+    var and = function(a, b) {
+        if (a) {
+            if (b) {
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    };
+
+    var or = function(a, b) {
+        if (a) {
+            return true;
+        } else {
+            if (b) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+    };
+
+    var map = function(fn, l) {
+        if (is_empty(l)) {
+            return empty_list;
+        } else {
+            return prepend(fn(head(l)), map(fn, tail(l)));
+        }
+    };
+
+    var filter = function(fn, l) {
+        if (is_empty(l)) {
+            return empty_list;
+        } else if (fn(head(l))) {
+            return prepend(head(l), filter(fn, tail(l)));
+        } else {
+            return filter(fn, tail(l));
+        }
+    };
+
+Before you move on, make sure all of this code is crystal clear.  Come back
+tomorrow if you need to let it sink in.  We're about to go a lot deeper into the
+rabbit hole, so make sure you're ready.
+
+Numbers
+-------
+
+If you look at the definitions of `prepend`, `head`, and `tail`, they're pretty
+mind-bending.  However, the definitions of `map` and `filter` are much more
+straightforward.
+
+This is because we encapsulated the implementation of lists into the first four
+functions.  We did all the hard work of building lists out of almost nothing at
+all and hid it behind that simple `prepend`, `head`, and `tail` interface.
+
+The idea of creating things from simple pieces and abstracting them into "black
+boxes" is one of the most important parts of both computer science and
+programming, so let's take it a step further and get some more practice by
+implementing numbers.
+
+### What is a Number?
+
+For this blog post we're only going to concern ourselves with non-negative
+integers.  Feel free to try extending all this to include negative integers if
+you want more.
+
+How can we represent a number?  Well we could obviously use Javascript numbers
+like `14`, but that's not very fun, and we're trying to minimize the number of
+language features we use.
+
+One way to represent a number is a list whose length is the number.  So we could
+say that `[1, 1, 1]` means "three", `["cats", null]` means "two", and `[]` means
+"zero".
+
+The elements themselves don't really matter, so let's just pick something we
+already have: the empty list!  Let's write out a few to get a feel for this:
+
+    :::javascript
+    var zero = empty_list;
+    // []
+
+    var one = prepend(empty_list, empty_list);
+    // [ [] ]
+
+    var two = prepend(empty_list, prepend(empty_list, empty_list));
+    // [ [], [] ]
+
+### inc, dec
+
+We're going to want to *do* things with our numbers, so let's start writing
+things that work with this "list of things" representation of numbers.
+
+Our basic building blocks are going to be `inc` and `dec` (increment and
+decrement).
+
+    :::javascript
+    var inc = function(n) {
+        return prepend(empty_list, n);
+    };
+
+    var dec = function(n) {
+        return tail(n);
+    };
+
+To add 1 to a number, we just push another element on the list.  So
+`inc(inc(zero))` means "two".
+
+To subtract 1, we just pop off one of the elements: `dec(two)` means "one"
+(remember we're ignoring negative numbers).
+
+### is\_zero
+
+When we started working with lists we used `is_empty` a lot, so it's probably
+a good idea to create an `is_zero` function at this point:
+
+    :::javascript
+    var is_zero = function(n) {
+        return is_empty(n);
+    };
+
+Zero is just represented by the empty list, so this one is easy!
+
+### add
+
+Adding one is easy, but we're probably going to want to add arbitrary numbers
+together.  Now that we have `inc` and `dec` this is actually pretty easy:
+
+    :::javascript
+    var add = function(a, b) {
+        if (is_zero(b)) {
+            return a;
+        } else {
+            return add(inc(a), dec(b));
+        }
+    };
+
+This is another recursive definition.  When adding two numbers, there are two
+possibilities:
+
+* If `b` is zero, then anything plus zero is zero, so we can just return `a`.
+* Otherwise, adding `a + b` is the same as adding `(a + 1) + (b - 1)`.
+
+Eventually `b` will "bottom out" and return `a` (which has been steadily getting
+bigger as `b` got smaller).
+
+Notice how we didn't say anything about lists here!  The "numbers are lists
+under the hood" idea has been encapsulated behind `is_zero`, `inc`, and `dec`,
+so we can ignore it and work at the "number" level of abstraction from here on
+out.
+
+### sub
+
+Subtraction is similar to addition, but instead of *increasing* `a` as `b` gets
+smaller, we *decrease* them both together:
+
+    :::javascript
+    var sub = function(a, b) {
+        if (is_zero(b)) {
+            return a;
+        } else {
+            return add(dec(a), dec(b));
+        }
+    };
+
+Now we can say something like `add(two, sub(three, two))` and the result will be
+a representation of "three" in our system (which, of course, is a list of three
+elements).
+
+Pause for a minute now and remember that underneath numbers are lists, and
+underneath lists there's nothing but functions.  We can add and subtract
+integers and underneath it all it's just functions shuffling around, expanding
+into other functions and contracting as they're called, and this writhing mass
+of lambdas somehow ends up representing `1 + 1 = 2`.  That's pretty cool!
+
+### mul, pow
+
+For practice let's create a way to multiply numbers:
+
+    :::javascript
+    var mul = function(a, b) {
+        if (is_zero(b)) {
+            return zero;
+        } else {
+            return add(a, mul(a, dec(b)));
+        }
+    };
+
+Building on `add` makes this pretty easy.  `3 * 4` is the same as `3
++ 3 + 3 + 3 + 0`.  Trace out the execution on paper if things are starting to
+get away from you.  Carry on when you're ready.
+
+`pow` ("power" or exponential) follows a similar structure as `mul`, but instead
+of adding together the copies we multiply them, and our base is one instead of
+zero:
+
+    :::javascript
+    var pow = function(a, b) {
+        if (is_zero(b)) {
+            return one;
+        } else {
+            return mul(a, pow(a, dec(b)));
+        }
+    };
+
+### is\_equal
+
+A common thing to do with numbers is to check if two are equal, so let's write
+that:
+
+    :::javascript
+    var is_equal = function(n, m) {
+        if (and(is_zero(n), is_zero(m))) {
+            return true;
+        } else if (or(is_zero(n), is_zero(m))) {
+            return false;
+        } else {
+            return is_equal(dec(n), dec(m));
+        }
+    };
+
+There are three cases here:
+
+* If both numbers are zero, they are equal.
+* If only one number is zero (but not both, or the first case would have caught
+  it), then they are *not* equal.
+* Otherwise, subtract one from each and try again.
+
+When calling this function with two non-zero numbers, both will be decremented
+in tandem until one of them bottoms out at zero first, or until they bottom out
+at the same time.
+
+### less\_than, greater\_than
+
+We can take a similar approach to implementing `less_than`:
+
+    :::javascript
+    var less_than = function(a, b) {
+        if (and(is_zero(a), is_zero(b))) {
+            return false;
+        } else if (is_zero(a)) {
+            return true;
+        } else if (is_zero(b)) {
+            return false;
+        } else {
+            return less_than(dec(a), dec(b));
+        }
+    };
+
+The difference here is that we have four cases.
+
+* If both numbers are zero, then `a` is not less than `b`.
+* Otherwise if `a` is zero (and we know `b` isn't) then yes, `a` is less than
+  `b`.
+* Otherwise if `b` is zero (and we know that `a` isn't) then no, `a` cannot be
+  less than `b` (remember that we're ignoring negative numbers).
+* Otherwise decrement both and try again.
+
+Once again, both numbers race to bottom out, and the outcome is decided by which
+one bottoms out first.
+
+We could do something similar for `greater_than`, but let's do it the easy way
+instead:
+
+    :::javascript
+    var greater_than = function(a, b) {
+        return less_than(b, a);
+    };
+
+### div, mod
+
+Once we have `less_than` we're ready to implement division and remainders:
+
+    :::javascript
+    var div = function(a, b) {
+        if (less_than(a, b)) {
+            return zero;
+        } else {
+            return inc(div(sub(a, b), b));
+        }
+    };
+
+    var rem = function(a, b) {
+        if (less_than(a, b)) {
+            return a;
+        } else {
+            return rem(sub(a, b), b);
+        }
+    };
+
+This pair is a bit more complicated than the three other basic operations
+because we can't deal with negative numbers.  Make sure you understand how it
+works.
+
+Full Circle
+-----------
+
+At this point, we have a (very basic) working system of numbers built on top of
+lists.  Let's chase our tails a bit and implement a few more list functions that
+use numbers.
+
+### nth
+
+To get the Nth item in a list, we just pop things off of it as we decrement
+N until we hit zero:
+
+    :::javascript
+    var nth = function(l, n) {
+        if (is_zero(n)) {
+            return head(l);
+        } else {
+            return nth(tail(l), dec(n));
+        }
+    };
+
+Under the hood there are really *two* lists getting things popped off as we
+iterate, because `n` is a number, which is a list, and `dec` pops things off.
+But it's much easier to read when we've abstracted away the representation of
+numbers, don't you think?
+
+### drop, take
+
+Two handy functions for working with lists are `drop` and `take`.
+
+`drop(l, three)` will return the list with the first three elements removed.
+
+`take(l, three)` will return the list containing only the first three elements.
+
+    :::javascript
+    var drop = function(l, n) {
+        if (is_zero(n)) {
+            return l;
+        } else {
+            return drop(tail(l), dec(n));
+        }
+    };
+
+    var take = function(l, n) {
+        if (is_zero(n)) {
+            return empty_list;
+        } else {
+            return prepend(head(l), take(tail(l), dec(n)));
+        }
+    };
+
+### slice
+
+Slicing a list is easy now that we have `drop`, `take`, and the ability to
+subtract numbers:
+
+    :::javascript
+    var slice = function(l, start, end) {
+        return take(drop(l, start), sub(end, start));
+    };
+
+First we drop up to the start, then take enough to get us to the end.
+
+### length
+
+We can define `length` recursively like everything else:
+
+    :::javascript
+    var length = function(l) {
+        if (is_empty(l)) {
+            return zero;
+        } else {
+            return inc(length(tail(l)));
+        }
+    };
+
+The length of the empty list is zero, and the length of any non-empty list is
+one plus the length of its tail.
+
+If your mind isn't in knots by this point, consider the following:
+
+* Lists are made of functions.
+* Numbers are made of lists whose length represents the number.
+* `length` is a function that takes a list (which is a function) and returns
+  the length as a number (a list whose length represents the number).
+* We only just now got around to defining `length` even though we've been using
+  numbers (which use the *length* of a list to represent a number) for a while
+  now!
+
+Are you dizzy yet?  If not:
+
+    :::javascript
+    var mylist = prepend(empty_list,
+                         prepend(empty_list,
+                                 empty_list));
+    var mylistlength = length(mylist);
+
+`mylist` is a list of two empty lists.
+
+`mylistlength` is the length of `mylist`...  
+which is "two"...  
+which is represented by a list of two empty lists...  
+which is `mylist` itself!
+
+Conclusion
+----------
+
+If you liked this twisty little story, I highly recommend you check out [The
+Little Schemer][].  It was one of the first books that really changed how
+I thought about programming.  Don't be put off by the fact that it uses Scheme
+-- the language doesn't really matter.
+
+I've also created [a gist][] with all the code.  Feel free to fork it and use it
+for practice.
+
+You could add some more utility functions for practice writing recursively:
+
+* `append` to add an item to the end of a list.
+* `concat` to concatenate two lists.
+* `min` and `max` which take two numbers and return the minimum/maximum one.
+* `remove`, which is like filter except it only leaves the elements that return
+  `false` for the predicate.
+* `contains_number`, which checks if a specific number is inside a list of
+  numbers.
+
+Or if you want something more challenging, try implementing bigger concepts on
+top of the current ones:
+
+* Negative numbers.
+* Non-negative rational numbers.
+* Negative rational numbers.
+* Association lists (a data structure that associates keys with values).
+
+Remember: the point is not to create something that runs well on a physical
+computer.  Instead of thinking about how to make a particular combination of
+transistors and circuits have the right voltages, think about "computing" in the
+beautiful, perfect, abstract sense.
+
+[a gist]: https://gist.github.com/sjl/5277681
+
+    {% endblock article %}
+
--- a/layout/_post.html	Mon Nov 19 19:20:21 2012 -0500
+++ b/layout/_post.html	Sat Mar 30 14:10:03 2013 -0400
@@ -21,6 +21,9 @@
                     data-flattr-category="text"
                     data-flattr-button="compact"
                     href="http://stevelosh.com{{ page.url }}">Flattr</a>
+                <iframe style="border: 0; margin: 2px 0 -2px 0; padding: 0; margin-top: 2px;"
+                        src="https://www.gittip.com/sjl/widget.html"
+                        width="48pt" height="22pt"></iframe>
             </div>
 
         {% endif %}
--- a/media/css/pygments-monokai-light.css	Mon Nov 19 19:20:21 2012 -0500
+++ b/media/css/pygments-monokai-light.css	Sat Mar 30 14:10:03 2013 -0400
@@ -1,6 +1,6 @@
 /* @override http://localhost:8080/media/css/pygments-monokai-light.css */
 .codehilite .hll { background-color: #49483e }
-.codehilite .c { color: #75715e } /* Comment */
+.codehilite .c { color: #7A7663 } /* Comment */
 .codehilite .err { color: #960050; background-color: #1e0010 } /* Error */
 .codehilite .k { color: #00a8c8} /* Keyword */
 .codehilite .l { color: #ae81ff } /* Literal */
@@ -32,7 +32,7 @@
 .codehilite .nf { color: #75af00} /* Name.Function */
 .codehilite .nl { color: #111111 } /* Name.Label */
 .codehilite .nn { color: #111111} /* Name.Namespace */
-.codehilite .nx { color: #75af00 } /* Name.Other */
+.codehilite .nx { color: #111111 } /* Name.Other */
 .codehilite .py { color: #111111 } /* Name.Property */
 .codehilite .nt { color: #f92672 } /* Name.Tag */
 .codehilite .nv { color: #111111 } /* Name.Variable */
@@ -57,4 +57,4 @@
 .codehilite .vc { color: #111111 } /* Name.Variable.Class */
 .codehilite .vg { color: #111111 } /* Name.Variable.Global */
 .codehilite .vi { color: #111111 } /* Name.Variable.Instance */
-.codehilite .il { color: #ae81ff } /* Literal.Number.Integer.Long */
\ No newline at end of file
+.codehilite .il { color: #ae81ff } /* Literal.Number.Integer.Long */