XGitUrl: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=blobdiff_plain;f=week3.mdwn;h=477284245c5f48b88919c6b2a24ee18d9bd7d57d;hp=26760eb0c1c360fa5d49139b7220ddc14c3b85c2;hb=aaadc20de94685e29c35abbd865e5f35d194e7b9;hpb=fb0fff30796bbcb9a393638b684bac82d25a3ffe
diff git a/week3.mdwn b/week3.mdwn
index 26760eb0..47728424 100644
 a/week3.mdwn
+++ b/week3.mdwn
@@ 126,7 +126,10 @@ With sufficient ingenuity, a great many functions can be defined in the same way
##However...##
Some computable functions are just not definable in this way. The simplest function that *simply cannot* be defined using the resources we've so far developed is the Ackermann function:
+Some computable functions are just not definable in this way. We can't, for example, define a function that tells us, for whatever function `f` we supply it, what is the smallest integer `x` where `f x` is `true`.
+
+Neither do the resources we've so far developed suffice to define the
+[[!wikipedia Ackermann function]]:
A(m,n) =
 when m == 0 > n + 1
@@ 134,9 +137,9 @@ Some computable functions are just not definable in this way. The simplest funct
 else > A(m1, A(m,n1))
A(0,y) = y+1
 A(1,y) = y+2
 A(2,y) = 2y + 3
 A(3,y) = 2^(y+3) 3
+ A(1,y) = 2+(y+3)  3
+ A(2,y) = 2(y+3)  3
+ A(3,y) = 2^(y+3)  3
A(4,y) = 2^(2^(2^...2)) [where there are y+3 2s]  3
...
@@ 146,11 +149,90 @@ But functions like the Ackermann function require us to develop a more general t
##How to do recursion with lowercase omega##
...
+Recall our initial, abortive attempt above to define the `get_length` function in the lambda calculus. We said "What we really want to do is something like this:
+
+ \lst. (isempty lst) zero (add one (... (extracttail lst)))
+
+where this very same formula occupies the `...` position."
+
+We are not going to exactly that, at least not yet. But we are going to do something close to it.
+
+Consider a formula of the following form (don't worry yet about exactly how we'll fill the `...`s):
+
+ \h \lst. (isempty lst) zero (add one (... (extracttail lst)))
+
+Call that formula `H`. Now what would happen if we applied `H` to itself? Then we'd get back:
+
+ \lst. (isempty lst) zero (add one (... (extracttail lst)))
+
+where any occurrences of `h` inside the `...` were substituted with `H`. Call this `F`. `F` looks pretty close to what we're after: a function that takes a list and returns zero if it's empty, and so on. And `F` is the result of applying `H` to itself. But now inside `F`, the occurrences of `h` are substituted with the very formula `H` we started with. So if we want to get `F` again, all we have to do is apply `h` to itselfsince as we said, the selfapplication of `H` is how we created `F` in the first place.
+
+So, the way `F` should be completed is:
+
+ \lst. (isempty lst) zero (add one ((h h) (extracttail lst)))
+
+and our original `H` is:
+
+ \h \lst. (isempty lst) zero (add one ((h h) (extracttail lst)))
+
+The selfapplication of `H` will give us `F` with `H` substituted in for its free variable `h`.
+
+Instead of writing out a long formula twice, we could write:
+
+ (\x. x x) LONGFORMULA
+
+and the initial `(\x. x x)` is just what we earlier called the ω
combinator (lowercase omega, not the nonterminating Ω
). So the selfapplication of `H` can be written:
+
+ω (\h \lst. (isempty lst) zero (add one ((h h) (extracttail lst))))
+
+and this will indeed implement the recursive function we couldn't earlier figure out how to define.
+
+In broad brushstrokes, `H` is half of the `get_length` function we're seeking, and `H` has the form:
+
+ \h otherarguments. ... (h h) ...
+
+We get the whole `get_length` function by applying `H` to itself. Then `h` is replaced by the half `H`, and when we later apply `h` to itself, we recreate the whole `get_length` again.
+
+##Neat! Can I make it easier to use?##
+
+Suppose you wanted to wrap this up in a pretty interface, so that the programmer didn't need to write `(h h)` but could just write `g` for some function `g`. How could you do it?
+
+Now the `F`like expression we'd be aiming forcall it `F*`would look like this:
+
+ \lst. (isempty lst) zero (add one (g (extracttail lst)))
+
+or, abbreviating:
+
+ \lst. ...g...
+
+Here we have just a single `g` instead of `(h h)`. We'd want `F*` to be the result of selfapplying some `H*`, and then binding to `g` that very selfapplication of `H*`. We'd get that if `H*` had the form:
+
+ \h. (\g lst. ...g...) (h h)
+
+The selfapplication of `H*` would be:
+
+ (\h. (\g lst. ...g...) (h h)) (\h. (\g lst. ...g...) (h h))
+
+or:
+
+ (\f. (\h. f (h h)) (\h. f (h h))) (\g lst. ...g...)
+
+The lefthand side of this is known as **the Ycombinator** and so this could be written more compactly as:
+
+ Y (\g lst. ...g...)
+
+or, replacing the abbreviated bits:
+
+ Y (\g lst. (isempty lst) zero (add one (g (extracttail lst))))
+
+So this is another way to implement the recursive function we couldn't earlier figure out how to define.
+
##Generalizing##
In general, a **fixed point** of a function f is a value *x* such that fx is equivalent to *x*. For example, what is a fixed point of the function from natural numbers to their squares? What is a fixed point of the successor function?
+Let's step back and fill in some theory to help us understand why these tricks work.
+
+In general, we call a **fixed point** of a function f any value *x* such that f x is equivalent to *x*. For example, what is a fixed point of the function from natural numbers to their squares? What is a fixed point of the successor function?
In the lambda calculus, we say a fixed point of an expression `f` is any formula `X` such that:
@@ 170,39 +252,39 @@ who knows what we'd get back? Perhaps there's some nonnumberrepresenting formu
Yes! That's exactly right. And which formula this is will depend on the particular way you've implemented the successor function.
Moreover, the recipes that enable us to name fixed points for any given formula aren't *guaranteed* to give us *terminating* fixed points. They might give us formulas X such that neither `X` nor `f X` have normal forms. (Indeed, what they give us for the square function isn't any of the Church numerals, but is rather an expression with no normal form.) However, if we take care we can ensure that we *do* get terminating fixed points. And this gives us a principled, fully general strategy for doing recursion. It lets us define even functions like the Ackermann function, which were until now out of our reach. It would let us define arithmetic and list functions on the "version 1" and "version 2" implementations, where it wasn't always clear how to force the computation to "keep going."
+Moreover, the recipes that enable us to name fixed points for any given formula aren't *guaranteed* to give us *terminating* fixed points. They might give us formulas X such that neither `X` nor `f X` have normal forms. (Indeed, what they give us for the square function isn't any of the Church numerals, but is rather an expression with no normal form.) However, if we take care we can ensure that we *do* get terminating fixed points. And this gives us a principled, fully general strategy for doing recursion. It lets us define even functions like the Ackermann function, which were until now out of our reach. It would also let us define arithmetic and list functions on the "version 1" and "version 2" implementations, where it wasn't always clear how to force the computation to "keep going."
OK, so how do we make use of this?
Recall our initial, abortive attempt above to define the `get_length` function in the lambda calculus. We said "What we really want to do is something like this:
+Recall again our initial, abortive attempt above to define the `get_length` function in the lambda calculus. We said "What we really want to do is something like this:
\lst. (isempty lst) zero (add one (... (extracttail lst)))
where this very same formula occupies the `...` position."
Now, what if we *were* somehow able to get ahold of this formula, as an additional argument? We could take that argument and plug it into the `...` position. Something like this:
+If we could somehow get ahold of this very formula, as an additional argument, then we could take the argument and plug it into the `...` position. Something like this:
\self (\lst. (isempty lst) zero (add one (self (extracttail lst))) )
This is an abstract of the form:
 \self. body
+ \self. BODY
where `body` is the expression:
+where `BODY` is the expression:
\lst. (isempty lst) zero (add one (self (extracttail lst)))
containing an occurrence of `self`.
Now consider what would be a fixed point of our expression `\self. body`? That would be some expression `X` such that:
+Now consider what would be a fixed point of our expression `\self. BODY`? That would be some expression `X` such that:
 X <~~> (\self.body) X
+ X <~~> (\self.BODY) X
Betareducing the righthand side, we get:
 X <~~> body [self := X]
+ X <~~> BODY [self := X]
Think about what this says. It says if you substitute `X` for `self` in our formula body:
+Think about what this says. It says if you substitute `X` for `self` in our formula BODY:
\lst. (isempty lst) zero (add one (X (extracttail lst)))
@@ 244,9 +326,9 @@ containing free occurrences of `self` that you treat as being equivalent to the
\lst. (isempty lst) zero (add one (self (extracttail lst)))
You bind the free occurrence of `self` as: `\self. body`. And then you generate a fixed point for this larger expression:
+You bind the free occurrence of `self` as: `\self. BODY`. And then you generate a fixed point for this larger expression:
Ψ (\self. body)
+Ψ (\self. BODY)
using some fixedpoint combinator Ψ
.
@@ 254,14 +336,14 @@ Isn't that cool?
##Okay, then give me a fixedpoint combinator, already!##
Many fixedpoint combinators have been discovered. (And given a fixedpoint combinators, there are ways to use it as a model to build infinitely many more, nonequivalent fixedpoint combinators.)
+Many fixedpoint combinators have been discovered. (And some fixedpoint combinators give us models for building infinitely many more, nonequivalent fixedpoint combinators.)
Two of the simplest:
Θ′ ≡ (\u f. f (\n. u u f n)) (\u f. f (\n. u u f n))
Y′ ≡ \f. (\u. f (\n. u u n)) (\u. f (\n. u u n))
Θ′ has the advantage that f (Θ′ f)
really *reduces to* Θ′ f
. f (Y′ f)
is only convertible with Y′ f
; that is, there's a common formula they both reduce to. For most purposes, though, either will do.
+Θ′
has the advantage that f (Θ′ f)
really *reduces to* Θ′ f
. Whereas f (Y′ f)
is only *convertible with* Y′ f
; that is, there's a common formula they both reduce to. For most purposes, though, either will do.
You may notice that both of these formulas have etaredexes inside them: why can't we simplify the two `\n. u u f n` inside Θ′
to just `u u f`? And similarly for Y′
?
@@ 270,9 +352,9 @@ Indeed you can, getting the simpler:
Θ ≡ (\u f. f (u u f)) (\u f. f (u u f))
Y ≡ \f. (\u. f (u u)) (\u. f (u u))
I stated the more complex formulas for the following reason: in a language whose evaluation order is *callbyvalue*, the evaluation of Θ (\self. body)
and `Y (\self. body)` will in general not terminate. But evaluation of the etaunreduced primed versions will.
+I stated the more complex formulas for the following reason: in a language whose evaluation order is *callbyvalue*, the evaluation of Θ (\self. BODY)
and `Y (\self. BODY)` will in general not terminate. But evaluation of the etaunreduced primed versions will.
Of course, if you define your `\self. body` stupidly, your formula will never terminate. For example, it doesn't matter what fixed point combinator you use for Ψ
in:
+Of course, if you define your `\self. BODY` stupidly, your formula will never terminate. For example, it doesn't matter what fixed point combinator you use for Ψ
in:
Ψ (\self. \n. self n)
@@ 317,7 +399,3 @@ then this is a fixedpoint combinator:
L L L L L L L L L L L L L L L L L L L L L L L L L L

[TODO: Explain how what we've done relates to the version using lowercase ω.]

