index 6d78f0b..1289713 100644 (file)
@@ -17,12 +17,12 @@ can use.
native `let rec` or `define`, then you can't use the fixed-point combinators
`Y` or <code>&Theta;</code>. Expressions using them will have non-terminating
reductions, with Scheme's eager/call-by-value strategy. There are other
native `let rec` or `define`, then you can't use the fixed-point combinators
`Y` or <code>&Theta;</code>. Expressions using them will have non-terminating
reductions, with Scheme's eager/call-by-value strategy. There are other
-       fixed-point combinators you can use with Scheme (in the [[week 3]] notes they
+       fixed-point combinators you can use with Scheme (in the [week 3 notes](/week3/#index7h2) they
were <code>Y&prime;</code> and <code>&Theta;&prime;</code>. But even with
were <code>Y&prime;</code> and <code>&Theta;&prime;</code>. But even with
-       those evaluation order still matters: for some (admittedly unusual)
+       them, evaluation order still matters: for some (admittedly unusual)
evaluation strategies, expressions using them will also be non-terminating.

evaluation strategies, expressions using them will also be non-terminating.

-       The fixed-point combinators may be the conceptual heros. They are cool and
+       The fixed-point combinators may be the conceptual stars. They are cool and
mathematically elegant. But for efficiency and implementation elegance, it's
best to know how to do as much as you can without them. (Also, that knowledge
could carry over to settings where the fixed point combinators are in
mathematically elegant. But for efficiency and implementation elegance, it's
best to know how to do as much as you can without them. (Also, that knowledge
could carry over to settings where the fixed point combinators are in
@@ -30,10 +30,10 @@ can use.

This is why the v3 lists and numbers are so lovely. However, one disadvantage
to them is that it's relatively inefficient to extract a list's tail, or get a

This is why the v3 lists and numbers are so lovely. However, one disadvantage
to them is that it's relatively inefficient to extract a list's tail, or get a
-       number's predecessor. To get the tail of the list [a;b;c;d;e], one will
+       number's predecessor. To get the tail of the list `[a;b;c;d;e]`, one will
basically be performing some operation that builds up the tail afresh: at
basically be performing some operation that builds up the tail afresh: at
-       different stages, one will have built up [e], then [d;e], then [c;d;e], and
-       finally [b;c;d;e]. With short lists, this is no problem, but with longer lists
+       different stages, one will have built up `[e]`, then `[d;e]`, then `[c;d;e]`, and
+       finally `[b;c;d;e]`. With short lists, this is no problem, but with longer lists
it takes longer and longer. And it may waste more of your computer's memory
than you'd like. Similarly for obtaining a number's predecessor.

it takes longer and longer. And it may waste more of your computer's memory
than you'd like. Similarly for obtaining a number's predecessor.

@@ -44,7 +44,7 @@ can use.

A clever approach would marry these two strategies.

A clever approach would marry these two strategies.

-       Version 3 makes the list [a; b; c; d; e] look like this:
+       Version 3 makes the list `[a;b;c;d;e]` look like this:

\f z. f a (f b (f c (f d (f e z))))

\f z. f a (f b (f c (f d (f e z))))

@@ -56,22 +56,22 @@ can use.

\f z. f a <the tail itself> <the result of folding f and z over the tail>

\f z. f a <the tail itself> <the result of folding f and z over the tail>

-       That is, now f is a function expecting *three* arguments: the head of the
+       That is, now `f` is a function expecting *three* arguments: the head of the
current list, the tail of the current list, and the result of continuing to
current list, the tail of the current list, and the result of continuing to
-       fold f over the tail, with a given base value z.
+       fold `f` over the tail, with a given base value `z`.

-       Call this a **version 4** list. The empty list could be the same:
+       Call this a **version 4** list. The empty list can be the same as in v3:

-               empty === \f z. z
+       <pre><code>empty &equiv; \f z. z</code></pre>

The list constructor would be:

The list constructor would be:

-               make_list === \h t. \f z. f h t (t f z)
+       <pre><code>make_list &equiv; \h t. \f z. f h t (t f z)</code></pre>

It differs from the version 3 `make_list` only in adding the extra argument
`t` to the new, outer application of `f`.

It differs from the version 3 `make_list` only in adding the extra argument
`t` to the new, outer application of `f`.

-       Similarly, 5 as a v3 or Church numeral looks like this:
+       Similarly, `five` as a v3 or Church numeral looks like this:

\s z. s (s (s (s (s z))))

\s z. s (s (s (s (s z))))

@@ -83,8 +83,8 @@ can use.

\s z. s <pred 5> <the result of applying s to z (pred 5)-many times>

\s z. s <pred 5> <the result of applying s to z (pred 5)-many times>

-       That is, now s is a function expecting *two* arguments: the predecessor of the
-       current number, and the result of continuing to apply s to the base value z
+       That is, now `s` is a function expecting *two* arguments: the predecessor of the
+       current number, and the result of continuing to apply `s` to the base value `z`
predecessor-many times.

Jim had the pleasure of "inventing" these implementations himself. However,
predecessor-many times.

Jim had the pleasure of "inventing" these implementations himself. However,
@@ -117,7 +117,7 @@ can use.
of a new list with the added member prepended to the old list. That is:

let empty_set = empty  in
of a new list with the added member prepended to the old list. That is:

let empty_set = empty  in
-               ; see the library for definition of any
+               ; see the library for definitions of any and eq
let make_set = \new_member old_set. any (eq new_member) old_set
; if any element in old_set was eq new_member
old_set
let make_set = \new_member old_set. any (eq new_member) old_set
; if any element in old_set was eq new_member
old_set
@@ -144,7 +144,7 @@ can use.
How might we make the implementation more efficient? Well, the *semantics* of
sets says that they have no intrinsic order. That means, there's no difference
between the set {a,b} and the set {b,a}; whereas there is a difference between
How might we make the implementation more efficient? Well, the *semantics* of
sets says that they have no intrinsic order. That means, there's no difference
between the set {a,b} and the set {b,a}; whereas there is a difference between
-       the *list* [a;b] and the list [b;a]. But this semantic point can be respected
+       the *list* `[a;b]` and the list `[b;a]`. But this semantic point can be respected
even if we *implement* sets with something ordered, like list---as we're
already doing. And we might *exploit* the intrinsic order of lists to make our
implementation of sets more efficient.
even if we *implement* sets with something ordered, like list---as we're
already doing. And we might *exploit* the intrinsic order of lists to make our
implementation of sets more efficient.
@@ -157,8 +157,8 @@ can use.
d)`.)

So, if we were searching the list that implements some set to see if the number
d)`.)

So, if we were searching the list that implements some set to see if the number
-       5 belonged to it, once we get to elements in the list that are larger than 5,
-       we can stop. If we haven't found 5 already, we know it's not in the rest of the
+       `5` belonged to it, once we get to elements in the list that are larger than `5`,
+       we can stop. If we haven't found `5` already, we know it's not in the rest of the
list either.

This is an improvement, but it's still a "linear" search through the list.
list either.

This is an improvement, but it's still a "linear" search through the list.
@@ -190,8 +190,8 @@ can use.
But what if you're using v3 lists? What options would you have then for
aborting a search?

But what if you're using v3 lists? What options would you have then for
aborting a search?

-       Well, suppose we're searching through the list [5; 4; 3; 2; 1] to see if it
-       contains the number 3. The expression which represents this search would have
+       Well, suppose we're searching through the list `[5;4;3;2;1]` to see if it
+       contains the number `3`. The expression which represents this search would have
something like the following form:

..................<eq? 1 3>  ~~>
something like the following form:

..................<eq? 1 3>  ~~>
@@ -204,13 +204,13 @@ can use.

Of course, whether those reductions actually followed in that order would
depend on what reduction strategy was in place. But the result of folding the

Of course, whether those reductions actually followed in that order would
depend on what reduction strategy was in place. But the result of folding the
-       search function over the part of the list whose head is 3 and whose tail is [2;
-       1] will *semantically* depend on the result of applying that function to the
+       search function over the part of the list whose head is `3` and whose tail is `[2;
+       1]` will *semantically* depend on the result of applying that function to the
more rightmost pieces of the list, too, regardless of what order the reduction
is computed by. Conceptually, it will be easiest if we think of the reduction
happening in the order displayed above.

more rightmost pieces of the list, too, regardless of what order the reduction
is computed by. Conceptually, it will be easiest if we think of the reduction
happening in the order displayed above.

-       Well, once we've found a match between our sought number 3 and some member of
+       Well, once we've found a match between our sought number `3` and some member of
the list, we'd like to avoid any further unnecessary computations and just
deliver the answer `true` as "quickly" or directly as possible to the larger
computation in which the search was embedded.
the list, we'd like to avoid any further unnecessary computations and just
deliver the answer `true` as "quickly" or directly as possible to the larger
computation in which the search was embedded.
@@ -220,11 +220,11 @@ can use.

But with the v3 lists, the fold is "pre-programmed" to continue over the whole
list. There is no way for us to bail out of applying the search function to the

But with the v3 lists, the fold is "pre-programmed" to continue over the whole
list. There is no way for us to bail out of applying the search function to the
-       parts of the list that have head 4 and head 5, too.
+       parts of the list that have head `4` and head `5`, too.

-       We *can* avoid some unneccessary computation. The search function can detect
-       that the result we've accumulated so far during the fold is now true, so we
-       don't need to bother comparing 4 or 5 to 3 for equality. That will simplify the
+       We *can* avoid *some* unneccessary computation. The search function can detect
+       that the result we've accumulated so far during the fold is now `true`, so we
+       don't need to bother comparing `4` or `5` to `3` for equality. That will simplify the
computation to some degree, since as we said, numerical comparison in the
system we're working in is moderately expensive.

computation to some degree, since as we said, numerical comparison in the
system we're working in is moderately expensive.

@@ -236,7 +236,7 @@ can use.
It would be better if there were some way to "abort" the list traversal. If,
having found the element we're looking for (or having determined that the
element isn't going to be found), we could just immediately stop traversing the
It would be better if there were some way to "abort" the list traversal. If,
having found the element we're looking for (or having determined that the
element isn't going to be found), we could just immediately stop traversing the
-       list with our answer. Continuations will turn out to let us do that.
+       list with our answer. **Continuations** will turn out to let us do that.

We won't try yet to fully exploit the terrible power of continuations. But
there's a way that we can gain their benefits here locally, without yet having

We won't try yet to fully exploit the terrible power of continuations. But
there's a way that we can gain their benefits here locally, without yet having
@@ -254,17 +254,22 @@ can use.

to get the first element of the pair. Of course you can lift that if you want:

to get the first element of the pair. Of course you can lift that if you want:

-               extract_1st === \pair. pair (\x y. x)
+       <pre><code>extract_fst &equiv; \pair. pair (\x y. x)</code></pre>

but at a lower level, the pair is still accepting its handler as an argument,
rather than the handler taking the pair as an argument. (The handler gets *the
pair's elements*, not the pair itself, as arguments.)

but at a lower level, the pair is still accepting its handler as an argument,
rather than the handler taking the pair as an argument. (The handler gets *the
pair's elements*, not the pair itself, as arguments.)

+       >       *Terminology*: we'll try to use names of the form `get_foo` for handlers, and
+       names of the form `extract_foo` for lifted versions of them, that accept the
+       lists (or whatever data structure we're working with) as arguments. But we may
+       sometimes forget.
+
The v2 implementation of lists followed a similar strategy:

v2list (\h t. do_something_with_h_and_t) result_if_empty

The v2 implementation of lists followed a similar strategy:

v2list (\h t. do_something_with_h_and_t) result_if_empty

-       If the v2list here is not empty, then this will reduce to the result of
+       If the `v2list` here is not empty, then this will reduce to the result of
supplying the list's head and tail to the handler `(\h t.
do_something_with_h_and_t)`.

supplying the list's head and tail to the handler `(\h t.
do_something_with_h_and_t)`.

@@ -281,11 +286,14 @@ can use.
semantically, the search is the argument and the larger computation is the
function to which it's supplied.

semantically, the search is the argument and the larger computation is the
function to which it's supplied.

-       What if, instead, we did the same kind of thing we did with pairs and v2 lists? That is, what if we made the larger computation a "handler" that we passed as an argument to the search?
+       What if, instead, we did the same kind of thing we did with pairs and v2
+       lists? That is, what if we made the larger computation a "handler" that we
+       passed as an argument to the search?

the_search (\search_result. larger_computation search_result other_arguments)

the_search (\search_result. larger_computation search_result other_arguments)

-       What's the advantage of that, you say. Other than to show off how cleverly you can lift.
+       What's the advantage of that, you say. Other than to show off how cleverly
+       you can lift.

Well, think about it. Think about the difficulty we were having aborting the
search. Does this switch-around offer us anything useful?

Well, think about it. Think about the difficulty we were having aborting the
search. Does this switch-around offer us anything useful?
@@ -294,20 +302,20 @@ can use.

What if the way we implemented the search procedure looked something like this?

What if the way we implemented the search procedure looked something like this?

-       At a given stage in the search, we wouldn't just apply some function f to the
+       At a given stage in the search, we wouldn't just apply some function `f` to the
head at this stage and the result accumulated so far, from folding the same
head at this stage and the result accumulated so far, from folding the same
-       function (and a base value) to the tail at this stage. And then pass the result
+       function (and a base value) to the tail at this stage...and then pass the result
of doing so leftward along the rest of the list.

of doing so leftward along the rest of the list.

-       We'd also give that function a "handler" that expected the result of the
-       current stage as an argument, and evaluated to passing that result leftwards
+       We'd *instead* give that function a "handler" that expected the result of the
+       current stage *as an argument*, and evaluated to passing that result leftwards
along the rest of the list.

Why would we do that, you say? Just more flamboyant lifting?

Well, no, there's a real point here. If we give the function a "handler" that
along the rest of the list.

Why would we do that, you say? Just more flamboyant lifting?

Well, no, there's a real point here. If we give the function a "handler" that
-       encodes the normal continuation of the fold leftwards through the list. We can
-       give it another "handler" as well. We can also give it the underlined handler:
+       encodes the normal continuation of the fold leftwards through the list, we can
+       also give it other "handlers" too. For example, we can also give it the underlined handler:

the_search (\search_result. larger_computation search_result other_arguments)

the_search (\search_result. larger_computation search_result other_arguments)
@@ -331,25 +339,25 @@ can use.

f 3 <result of folding f and z over [2; 1]> <handler to continue folding leftwards> <handler to abort the traversal>

f 3 <result of folding f and z over [2; 1]> <handler to continue folding leftwards> <handler to abort the traversal>

-       f's job would be to check whether 3 matches the element we're searching for
+       `f`'s job would be to check whether 3 matches the element we're searching for
(here also 3), and if it does, just evaluate to the result of passing `true` to
the abort handler. If it doesn't, then evaluate to the result of passing
`false` to the continue-leftwards handler.

(here also 3), and if it does, just evaluate to the result of passing `true` to
the abort handler. If it doesn't, then evaluate to the result of passing
`false` to the continue-leftwards handler.

-       In this case, f wouldn't need to consult the result of folding f and z over [2;
-       1], since if we had found the element 3 in more rightward positions of the
-       list, we'd have called the abort handler and this application of f to 3 etc
-       would never be needed. However, in other applications the result of folding f
-       and z over the more rightward parts of the list would be needed. Consider if
+       In this case, `f` wouldn't need to consult the result of folding `f` and `z` over `[2;
+       1]`, since if we had found the element `3` in more rightward positions of the
+       list, we'd have called the abort handler and this application of `f` to `3` etc
+       would never be needed. However, in other applications the result of folding `f`
+       and `z` over the more rightward parts of the list would be needed. Consider if
you were trying to multiply all the elements of the list, and were going to
you were trying to multiply all the elements of the list, and were going to
-       abort (with the result 0) if you came across any element in the list that was
+       abort (with the result `0`) if you came across any element in the list that was
zero. If you didn't abort, you'd need to know what the more rightward elements
of the list multiplied to, because that would affect the answer you passed
along to the continue-leftwards handler.

A **version 5** list would encode this kind of fold operation over the list, in
the same way that v3 (and v4) lists encoded the simpler fold operation.
zero. If you didn't abort, you'd need to know what the more rightward elements
of the list multiplied to, because that would affect the answer you passed
along to the continue-leftwards handler.

A **version 5** list would encode this kind of fold operation over the list, in
the same way that v3 (and v4) lists encoded the simpler fold operation.
-       Roughly, the list [5; 4; 3; 2; 1] would look like this:
+       Roughly, the list `[5;4;3;2;1]` would look like this:

\f z continue_leftwards_handler abort_handler.

\f z continue_leftwards_handler abort_handler.
@@ -371,20 +379,20 @@ can use.

Remarks: the `larger_computation_handler` should be supplied as both the
`continue_leftwards_handler` and the `abort_handler` for the leftmost

Remarks: the `larger_computation_handler` should be supplied as both the
`continue_leftwards_handler` and the `abort_handler` for the leftmost
-       application, where the head 5 is supplied to f. Because the result of this
+       application, where the head `5` is supplied to `f`. Because the result of this
application should be passed to the larger computation, whether it's a "fall
off the left end of the list" result or it's a "I'm finished, possibly early"
result. The `larger_computation_handler` also then gets passed to the next
application should be passed to the larger computation, whether it's a "fall
off the left end of the list" result or it's a "I'm finished, possibly early"
result. The `larger_computation_handler` also then gets passed to the next
-       rightmost stage, where the head 4 is supplied to f, as the `abort_handler` to
+       rightmost stage, where the head `4` is supplied to `f`, as the `abort_handler` to
use if that stage decides it has an early answer.

use if that stage decides it has an early answer.

-       Finally, notice that we don't have the result of applying f to 4 etc given as
-       an argument to the application of f to 5 etc. Instead, we pass
+       Finally, notice that we don't have the result of applying `f` to `4` etc given as
+       an argument to the application of `f` to `5` etc. Instead, we pass

(\result_of_fold_over_4321. f 5 result_of_fold_over_4321 one_handler another_handler)

(\result_of_fold_over_4321. f 5 result_of_fold_over_4321 one_handler another_handler)

-       *to* the application of f to 4 as its "continue" handler. The application of f
-       to 4 can decide whether this handler, or the other, "abort" handler, should be
+       *to* the application of `f` to `4` as its "continue" handler. The application of `f`
+       to `4` can decide whether this handler, or the other, "abort" handler, should be
given an argument and constitute its result.

given an argument and constitute its result.