sigh
authorChris Barker <barker@kappa.linguistics.fas.nyu.edu>
Sat, 2 Oct 2010 19:19:28 +0000 (15:19 -0400)
committerChris Barker <barker@kappa.linguistics.fas.nyu.edu>
Sat, 2 Oct 2010 19:19:28 +0000 (15:19 -0400)
12 files changed:
arithmetic.mdwn [new file with mode: 0644]
assignment3.mdwn
code/lambda.js
code/tokens.js
evaluation_order.mdwn [new file with mode: 0644]
index.mdwn
lists_and_numbers.mdwn
offsite_reading.mdwn
temp [deleted file]
temp.mdwn [deleted file]
week3.mdwn
y-combinator-fixed.jpg [new file with mode: 0644]

diff --git a/arithmetic.mdwn b/arithmetic.mdwn
new file mode 100644 (file)
index 0000000..fafecaf
--- /dev/null
@@ -0,0 +1,281 @@
+Here are a bunch of pre-tested operations for the untyped lambda calculus. In some cases multiple versions are offered.
+
+       ; booleans
+       let true = \y n. y  in ; aka K
+       let false = \y n. n  in ; aka K I
+       let and = \p q. p q false  in ; or
+       let and = \p q. p q p  in ; aka S C I
+       let or = \p q. p true q  in ; or
+       let or = \p q. p p q  in ; aka M
+       let not = \p. p false true  in ; or
+       let not = \p y n. p n y  in ; aka C
+       let xor = \p q. p (not q) q  in
+       let iff = \p q. not (xor p q)  in ; or
+       let iff = \p q. p q (not q)  in
+
+       ; pairs
+       let make_pair = \x y f. f x y  in
+       let get_1st = \x y. x  in ; aka true
+       let get_2nd = \x y. y  in ; aka false
+
+       ; triples
+       let make_triple = \x y z f. f x y z  in
+
+
+       ; Church numerals: basic operations
+
+       let zero = \s z. z  in ; aka false
+       let one = \s z. s z  in ; aka I
+       let succ = \n s z. s (n s z)  in
+       ; for any Church numeral n > zero : n (K y) z ~~> y
+       let iszero = \n. n (\x. false) true  in
+
+
+       ; version 3 lists
+
+       let empty = \f z. z  in
+       let make_list = \h t f z. f h (t f z)  in
+       let isempty = \lst. lst (\h sofar. false) true  in
+       let head = \lst. lst (\h sofar. h) junk  in
+       let tail_empty = empty  in
+       let tail = \lst. (\shift. lst shift (make_pair empty tail_empty) get_2nd)
+                               ; where shift is
+                               (\h p. p (\t y. make_pair (make_list h t) t))  in
+       let length = \lst. lst (\h sofar. succ sofar) 0  in
+       let map = \f lst. lst (\h sofar. make_list (f h) sofar) empty  in
+       let filter = \f lst. lst (\h sofar. f h (make_list h sofar) sofar) empty  in ; or
+       let filter = \f lst. lst (\h. f h (make_list h) I) empty  in
+       let singleton = \x f z. f x z  in
+       ; append [a;b;c] [x;y;z] ~~> [a;b;c;x;y;z]
+       let append = \left right. left make_list right  in
+       ; very inefficient but correct reverse
+       let reverse = \lst. lst (\h sofar. append sofar (singleton h)) empty  in ; or
+       ; more efficient reverse builds a left-fold instead
+       ; (make_left_list a (make_left_list b (make_left_list c empty)) ~~> \f z. f c (f b (f a z))
+       let reverse = (\make_left_list lst. lst make_left_list empty) (\h t f z. t f (f h z))  in
+       ; zip [a;b;c] [x; y; z] ~~> [(a,x);(b,y);(c,z)]
+       let zip = \left right. (\base build. reverse left build base (\x y. reverse x))
+                       ; where base is
+                       (make_pair empty (map (\h u. u h) right))
+                       ; and build is
+                       (\h sofar. sofar (\x y. isempty y
+                                               sofar
+                                               (make_pair (make_list (\u. head y (u h)) x)  (tail y))
+                       ))  in
+       let all = \f lst. lst (\h sofar. and sofar (f h)) true  in
+       let any = \f lst. lst (\h sofar. or sofar (f h)) false  in
+
+
+       ; version 1 lists
+
+       let empty = make_pair true junk  in
+       let make_list = \h t. make_pair false (make_pair h t)  in
+       let isempty = \lst. lst get_1st  in
+       let head = \lst. isempty lst err (lst get_2nd get_1st)  in
+       let tail_empty = empty  in
+       let tail = \lst. isempty lst tail_empty (lst get_2nd get_2nd)  in
+       
+
+       ; more math with Church numerals
+
+       let add = \m n. m succ n  in ; or
+       let add = \m n s z. m s (n s z)  in
+       let mul = \m n. m (\z. add n z) zero  in ; or
+       let mul = \m n s. m (n s)  in
+       let pow = \b exp. exp (mul b) one  in ; or
+       ; b succ : adds b
+       ; b (b succ) ; adds b b times, ie adds b^2
+       ; b (b (b succ)) ; adds b^2 b times, ie adds b^3
+       ; exp b succ ; adds b^exp
+       let pow = \b exp s z. exp b s z  in
+
+
+       ; three strategies for predecessor
+       let pred_zero = zero  in
+       let pred = (\shift n. n shift (make_pair zero pred_zero) get_2nd)
+               ; where shift is
+               (\p. p (\x y. make_pair (succ x) x))  in ; or
+       ; from Oleg; observe that for any Church numeral n: n I ~~> I
+       let pred = \n. iszero n zero
+                                       ; else
+                                       (n (\x. x I ; when x is the base term, this will be K zero
+                                                         ; when x is a Church numeral, it will be I
+                                               (succ x))
+                                         ; base term
+                                         (K (K zero))
+                                       )  in
+       ; from Bunder/Urbanek
+       let pred = \n s z. n (\u v. v (u s)) (K z) I  in ; or
+
+                                       
+       ; inefficient but simple comparisons
+       let leq = \m n. iszero (n pred m)  in
+       let lt = \m n. not (leq n m)  in
+       let eq = \m n. and (leq m n) (leq n m)  in ; or
+
+
+       ; more efficient comparisons, Oleg's gt provided some simplifications
+       let leq = (\base build consume. \m n. n consume (m build base) get_1st)
+                       ; where base is
+                       (make_pair true junk)
+                       ; and build is
+                       (\p. make_pair false p)
+                       ; and consume is
+                       (\p. p get_1st p (p get_2nd))  in
+       let lt = \m n. not (leq n m)  in
+       let eq = (\base build consume. \m n. n consume (m build base) get_1st)
+                       ; 2nd element of a pair will now be of the form (K sthg) or I
+                       ; we supply the pair being consumed itself as an argument
+                       ; getting back either sthg or the pair we just consumed
+                       ; base is
+                       (make_pair true (K (make_pair false I)))
+                       ; and build is
+                       (\p. make_pair false (K p))
+                       ; and consume is
+                       (\p. p get_2nd p)  in
+       
+
+       ; -n is a fixedpoint of \x. add (add n x) x
+       ; but unfortunately Y that_function doesn't normalize
+       ; instead:
+       let sub = \m n. n pred m  in ; or
+       ; how many times we can succ n until m <= result
+       let sub = \m n. (\base build. m build base (\cur fin sofar. sofar))
+                               ; where base is
+                               (make_triple n false zero)
+                               ; and build is
+                               (\t. t (\cur fin sofar. or fin (leq m cur)
+                                               (make_triple cur true sofar) ; enough
+                                               (make_triple (succ cur) false (succ sofar)) ; continue
+                               ))  in
+       ; or
+       let sub = (\base build consume. \m n. n consume (m build base) get_1st)
+                       ; where base is
+                       (make_pair zero I) ; see second defn of eq for explanation of 2nd element
+                       ; and build is
+                       (\p. p (\x y. make_pair (succ x) (K p)))
+                       ; and consume is
+                       (\p. p get_2nd p)  in
+
+
+       let min = \m n. sub m (sub m n) in
+       let max = \m n. add n (sub m n) in
+
+
+       ; (m/n) is a fixedpoint of \x. add (sub (mul n x) m) x
+       ; but unfortunately Y that_function doesn't normalize
+       ; instead:
+       ; how many times we can sub n from m while n <= result
+       let div = \m n. (\base build. m build base (\cur go sofar. sofar))
+                               ; where base is
+                               (make_triple m true zero)
+                               ; and build is
+                               (\t. t (\cur go sofar. and go (leq n cur)
+                                               (make_triple (sub cur n) true (succ sofar)) ; continue
+                                               (make_triple cur false sofar) ; enough
+                               ))  in
+    ; what's left after sub n from m while n <= result
+    let mod = \m n. (\base build. m build base (\cur go. cur))
+                ; where base is
+                (make_pair m true)
+                ; and build is
+                (\p. p (\cur go. and go (leq n cur)
+                        (make_pair (sub cur n) true) ; continue
+                        (make_pair cur false) ; enough
+                ))  in
+
+       ; or
+       let divmod = (\base build mtail. \m n.
+                                       (\dhead. m (mtail dhead) (\sel. dhead (sel 0 0)))
+                                                       (n build base (\x y z. z junk))
+                                                       (\t u x y z. make_pair t u) )
+                               ; where base is
+                               (make_triple succ (K 0) I) ; see second defn of eq for explanation of 3rd element
+                               ; and build is
+                       (\t. make_triple I succ (K t))
+                               ; and mtail is
+                               (\dhead d. d (\dz mz df mf drest sel. drest dhead (sel (df dz) (mf mz))))
+       in
+       let div = \n d. divmod n d get_1st  in
+       let mod = \n d. divmod n d get_2nd  in
+
+
+       ; sqrt n is a fixedpoint of \x. div (div (add n (mul x x)) 2) x
+       ; but unfortunately Y that_function doesn't normalize
+
+
+       ; (log base b of m) is a fixedpoint of \x. add (sub (pow b x) m) x
+       ; but unfortunately Y that_function doesn't normalize
+       ; instead:
+       ; how many times we can mul b by b while result <= m
+       let log = \m b. (\base build. m build base (\cur go sofar. sofar))
+               ; where base is
+               (make_triple b true 0)
+               ; and build is
+               (\t. t (\cur go sofar. and go (leq cur m)
+                          (make_triple (mul cur b) true (succ sofar)) ; continue
+                          (make_triple cur false sofar) ; enough
+               ))  in
+
+
+       ; Rosenbloom's fixed point combinator
+       let Y = \f. (\h. f (h h)) (\h. f (h h)) in
+       ; Turing's fixed point combinator
+       let Theta = (\u f. f (u u f)) (\u f. f (u u f))  in
+
+
+       ; length for version 1 lists
+       let length = Y (\self lst. isempty lst 0 (succ (self (tail lst))))  in
+
+
+       ; numhelper 0 f z ~~> z
+       ; when n > 0: numhelper n f z ~~> f (pred n)
+       ; compare Bunder/Urbanek pred
+       let numhelper = \n. n (\u v. v (u succ)) (K 0) (\p f z. f p)  in
+
+       ; accepts fixed point combinator as a parameter, so you can use different ones
+       let fact = \y. y (\self n. numhelper n (\p. mul n (self p)) 1)  in
+
+
+
+       fact Theta 3  ; returns 6
+
+
+<!--
+       ; my original efficient comparisons
+       let leq = (\base build consume. \m n. n consume (m build base) get_1st (\x. false) true)
+                       ; where base is
+                       (make_pair zero I) ; supplying this pair as an arg to its 2nd term returns the pair
+                       ; and build is
+                       (\p. p (\x y. make_pair (succ x) (K p))) ; supplying the made pair as an arg to its 2nd term returns p (the previous pair)
+                       ; and consume is
+                       (\p. p get_2nd p)  in
+       let lt = \m n. not (leq n m) in
+       let eq = (\base build consume. \m n. n consume (m build base) true (\x. false) true)
+                       ; where base is
+                       (make_pair zero (K (make_pair one I)))
+                       ; and build is
+                       (\p. p (\x y. make_pair (succ x) (K p)))
+                       ; and consume is
+                       (\p. p get_2nd p)  in ; or
+-->
+
+<!--
+       gcd
+       pow_mod
+
+
+       show Oleg's definition of integers:
+               church_to_int = \n sign. n
+               church_to_negint = \n sign s z. sign (n s z)
+
+               ; int_to_church
+               abs = \int. int I
+
+               sign_case = \int ifpos ifzero ifneg. int (K ifneg) (K ifpos) ifzero
+
+               negate_int = \int. sign_case int (church_to_negint (abs int)) zero (church_to_int (abs int))
+
+       for more, see http://okmij.org/ftp/Computation/lambda-arithm-neg.scm
+
+-->
index f93afd6..6f4f3f6 100644 (file)
@@ -4,9 +4,10 @@ Assignment 3
 Once again, the lambda evaluator will make working through this
 assignment much faster and more secure.
 
-##Writing recursive functions on version 1 style lists##
+#Writing recursive functions on version 1 style lists#
 
-Recall that version 1 style lists are constructed like this:
+Recall that version 1 style lists are constructed like this (see
+[[lists and numbers]]):
 
 <pre>
 ; booleans
@@ -35,18 +36,18 @@ let isZero = \n. n (\x. false) true in
 let succ = \n s z. s (n s z) in
 let mult = \m n s. m (n s) in
 let length = Y (\length l. isNil l 0 (succ (length (tail l)))) in
-let predecessor = \n. length (tail (n (\p. makeList meh p) nil)) in
-let leq = ; (leq m n) will be true iff m is less than or equal to n
-  Y (\leq m n. isZero m true (isZero n false (leq (predecessor m)(predecessor n)))) in
+let pred = \n. isZero n 0 (length (tail (n (\p. makeList meh p) nil)))
+in
+let leq = \m n. isZero(n pred m) in
 let eq = \m n. and (leq m n)(leq n m) in
 
-eq 3 3
+eq 2 2 yes no
 </pre>
 
 
 Then `length mylist` evaluates to 3.
 
-1. Warm-up: What does `head (tail (tail mylist))` evaluate to?
+1. What does `head (tail (tail mylist))` evaluate to?
 
 2. Using the `length` function as a model, and using the predecessor
 function, write a function that computes factorials.  (Recall that n!,
@@ -57,41 +58,84 @@ greater than 2 (it does't provide enough resources for the JavaScript
 interpreter; web pages are not supposed to be that computationally
 intensive).
 
-
-3. Write a function `listLenEq` that returns true just in case two lists have the
+3. (Easy) Write a function `listLenEq` that returns true just in case
+two lists have the
 same length.  That is,
 
-     listLenEq mylist (makeList meh (makeList meh (makeList meh nil))) ~~> true
+     listLenEq mylist (makeList meh (makeList meh (makeList meh nil)))
+     ~~> true
 
      listLenEq mylist (makeList meh (makeList meh nil))) ~~> false
 
-4. Now write the same function, but don't use the length function (hint: use `leq` as a model).
 
-##Trees##
+4. (Still easy) Now write the same function, but don't use the length
+function.
+
+5. In assignment 2, we discovered that version 3-type lists (the ones
+that
+work like Church numerals) made it much easier to define operations
+like `map` and `filter`.  But now that we have recursion in our
+toolbox,
+reasonable map and filter functions for version 1 lists are within our
+reach.  Give definitions for `map` and a `filter` for verson 1 type
+lists.
+
+#Computing with trees#
 
-Since we'll be working with linguistic objects, let's approximate
-trees as follows: a tree is a version 1 list
-a Church number is a tree, and 
-if A and B are trees, then (make-pair A B) is a tree.
+Linguists analyze natural language expressions into trees.  
+We'll need trees in future weeks, and tree structures provide good
+opportunities for learning how to write recursive functions.
+Making use of the resources we have at the moment, we can approximate
+trees as follows: instead of words, we'll use Church numerals.
+Then a tree will be a (version 1 type) list in which each element is
+itself a tree.  For simplicity, we'll adopt the convention that 
+a tree of length 1 must contain a number as its only element.  
+Then we have the following representations:
 
+<pre>
+   (a)           (b)             (c)  
+    .
+   /|\            /\              /\
+  / | \          /\ 3            1 /\
+  1 2  3        1  2               2 3
+
+[[1];[2];[3]]  [[[1];[2]];[3]]   [[1];[[2];[3]]]
+</pre>
 
+Limitations of this scheme include the following: there is no easy way
+to label a constituent with a syntactic category (S or NP or VP,
+etc.), and there is no way to represent a tree in which a mother has a
+single daughter.
 
+When processing a tree, you can test for whether the tree contains
+only a numeral (in which case the tree is leaf node) by testing for
+whether the length of the list is less than or equal to 1.  This will
+be your base case for your recursive functions that operate on these
+trees.
 
-[The following should be correct, but won't run in my browser:
+1.    Write a function that sums the number of leaves in a tree.
 
-let factorial = Y (\fac n. isZero n 1 (mult n (fac (predecessor n)))) in
+Expected behavior:
 
 <pre>
-let reverse = 
-  Y (\rev l. isNil l nil 
-                   (isNil (tail l) l 
-                          (makeList (head (rev (tail l))) 
-                                    (rev (makeList (head l) 
-                                                   (rev (tail (rev (tail l))))))))) in
-
-reverse (makeList 1 (makeList 2 (makeList 3 nil)))
+let t1 = (makeList 1 nil) in
+let t2 = (makeList 2 nil) in
+let t3 = (makeList 3 nil) in
+let t12 = (makeList t1 (makeList t2 nil)) in
+let t23 = (makeList t2 (makeList t3 nil)) in
+let ta = (makeList t1 t23) in
+let tb = (makeList t12 t3) in
+let tc = (makeList t1 (makeList t23 nil)) in
+
+sum-leaves t1 ~~> 1
+sum-leaves t2 ~~> 2
+sum-leaves t3 ~~> 3
+sum-leaves t12 ~~> 3
+sum-leaves t23 ~~> 5
+sum-leaves ta ~~> 6
+sum-leaves tb ~~> 6
+sum-leaves tc ~~> 6
 </pre>
 
-It may require more resources than my browser is willing to devote to
-JavaScript.]
+2.   Write a function that counts the number of leaves.
 
index 609cce0..50880fc 100644 (file)
@@ -207,11 +207,14 @@ function Lambda_var(variable) {
                        var res = left, x;
                        while (stack.length) {
                                x = stack.shift();
-                               res = new Lambda_app(res, x.eval_loop([], eta));
+                               // res = new Lambda_app(res, x.eval_loop([], eta));
+                               res = new Lambda_app(res, reduce(x, eta, false));
                        }
                        return res;
         }
-        return unwind(this, stack);
+        // return unwind(this, stack);
+               // trampoline to, args
+               return [null, unwind(this, stack)];
     };
     this.eval_cbv = function (aggressive) {
         return this;
@@ -261,7 +264,9 @@ function Lambda_app(left, right) {
     this.eval_loop = function (stack, eta) {
         var new_stack = stack.slice(0);
         new_stack.unshift(this.right);
-        return this.left.eval_loop(new_stack, eta);
+        // return this.left.eval_loop(new_stack, eta);
+               // trampoline to, args
+               return [this.left, new_stack, eta];
     };
     this.eval_cbv = function (aggressive) {
         var left = this.left.eval_cbv(aggressive);
@@ -355,16 +360,19 @@ function Lambda_lam(variable, body) {
     };
     this.eval_loop = function (stack, eta) {
         if (stack.length === 0) {
-            var term = new Lambda_lam(this.bound, this.body.eval_loop([], eta));
-            if (eta) {
-                return term.check_eta();
-            } else {
-                return term;
-            }
+                       // var term = new Lambda_lam(this.bound, this.body.eval_loop([], eta));
+                       var term = new Lambda_lam(this.bound, reduce(this.body, eta, false));
+                       if (eta) {
+                               return [null, term.check_eta()];
+                       } else {
+                               return [null, term];
+                       }
         } else {
             var x = stack[0];
             var xs = stack.slice(1);
-            return subst(this.bound, x, this.body).eval_loop(xs, eta);
+            // return subst(this.bound, x, this.body).eval_loop(xs, eta);
+                       // trampoline to, args
+                       return [subst(this.bound, x, this.body), xs, eta];
         }
     };
     this.eval_cbv = function (aggressive) {
@@ -414,7 +422,13 @@ function reduce(expr, eta, cbv) {
     if (cbv) {
         return expr.eval_cbv(cbv > 1);
     } else {
-        return expr.eval_loop([], eta);
+        // return expr.eval_loop([], eta);
+               var to_eval = expr, res = [[], eta];
+               while (to_eval !== null) {
+                       res = to_eval.eval_loop.apply(to_eval, res);
+                       to_eval = res.shift();
+               }
+               return res[0];
     }
 }
 
index 53639a8..ddf1e89 100644 (file)
@@ -81,7 +81,7 @@ String.prototype.tokens = function (prefix, suffix) {
             for (;;) {
                 c = this.charAt(i);
                 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
-                        (c >= '0' && c <= '9') || c === '_' || c === '-') {
+                        (c >= '0' && c <= '9') || c === '_' || c === '-' || c === '/') {
                     str += c;
                     i += 1;
                                } else if (c === '?' || c === '!') {
@@ -90,7 +90,7 @@ String.prototype.tokens = function (prefix, suffix) {
                     i += 1;
                                // make sure next character is not an identifier
                                        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
-                                               (c >= '0' && c <= '9') || c === '_' || c === '-' || c === '?' || c === '!') {
+                                               (c >= '0' && c <= '9') || c === '_' || c === '-' || c === '/' || c === '?' || c === '!') {
                                                str += c;
                                                i += 1;
                                                make('name', str).error("Bad identifier");
diff --git a/evaluation_order.mdwn b/evaluation_order.mdwn
new file mode 100644 (file)
index 0000000..3cd25fb
--- /dev/null
@@ -0,0 +1,125 @@
+This discussion elaborates on the discussion of evaluation order in the
+class notes from week 2.  It makes use of the reduction diagrams drawn
+in class, which makes choice of evaluation strategy a choice of which
+direction to move through a network of reduction links.
+
+
+Some lambda terms can be reduced in different ways:
+
+<pre>
+                     ((\x.x)((\y.y) z))
+                       /      \
+                      /        \  
+                     /          \
+                    /            \
+                    ((\y.y) z)   ((\x.x) z)
+                      \             /
+                       \           /
+                        \         /
+                         \       /
+                          \     /
+                           \   /
+                             z
+</pre>
+
+But because the lambda calculus is confluent (has the diamond
+property, named after the shape of the diagram above), no matter which
+lambda you choose to target for reduction first, you end up at the
+same place.  It's like travelling in Manhattan: if you walk uptown
+first and then head east, you end up in the same place as if you walk
+east and then head uptown.
+
+But which lambda you target has implications for efficiency and for 
+termination.  (Later in the course, it will have implications for
+the order in which side effects occur.)
+
+First, efficiency:
+
+<pre>
+                      ((\x.w)((\y.y) z))
+                        \      \
+                         \      ((\x.w) z)
+                          \       /
+                           \     /
+                            \   /
+                             \ /
+                              w    
+</pre>                    
+
+If a function discards its argument (as `\x.w` does), it makes sense
+to target that function for reduction, rather than wasting effort
+reducing the argument only to have the result of all that work thrown
+away.  So in this situation, the strategy of "always reduce the
+leftmost reducible lambda" wins.
+
+But:
+
+<pre>
+                        ((\x.xx)((\y.y) z))
+                          /       \
+     (((\y.y) z)((\y.y) z)         ((\x.xx) z)
+        /         |                  /
+       /          (((\y.y)z)z)      /
+      /              |             / 
+     /               |            /
+    /                |           /
+    (z ((\y.y)z))    |          / 
+         \           |         /
+          -----------.---------
+                     |
+                     zz
+</pre>
+
+This time, the leftmost function `\x.xx` copies its argument.
+If we reduce the rightmost lambda first (rightmost branch of the
+diagram), the argument is already simplified before we do the
+copying.  We arrive at the normal form (i.e., the form that cannot be
+further reduced) in two steps.  
+
+But if we reduce the rightmost lambda first (the two leftmost branches
+of the diagram), we copy the argument before it has been evaluated.
+In effect, when we copy the unreduced argument, we double the amount
+of work we need to do to deal with that argument.
+
+So when the function copies its argument, the "always reduce the
+rightmost reducible lambda" wins.
+
+So evaluation strategies have a strong effect on how many reduction
+steps it takes to arrive at a stopping point (e.g., normal form).
+
+Now for termination:
+
+<pre>
+(\x.w)((\x.xxx)(\x.xxx))
+ |      \
+ |       (\x.w)((\x.xxx)(\x.xxx)(\x.xxx))
+ |        /      \
+ |       /        (\x.w)((\x.xxx)(\x.xxx)(\x.xxx)(\x.xxx))
+ |      /          /       \
+ .-----------------         etc.
+ |
+ w
+</pre>
+
+Here we have a function that discards its argument on the left, and a
+non-terminating term on the right.  It's even more evil than Omega,
+because it not only never reduces, it generates more and more work
+with each so-called reduction.  If we unluckily adopt the "always
+reduce the rightmost reducible lambda" strategy, we'll spend our days
+relentlessly copying out new copies of \x.xxx.  But if we even once
+reduce the leftmost reducible lambda, we'll immediately jump to the
+normal form, `w`.
+
+We can roughly associate the "leftmost always" strategy with call by
+name (normal order), and the "rightmost always" strategy with call by
+value (applicative order).  There are fine-grained distinctions among
+these terms of art that we will not pause to untangle here.
+
+If a term has a normal form (a reduction such that no further
+reduction is possible), then a leftmost-always reduction will find it.
+(That's why it's called "normal order": it's the evaluation order that
+guarantees finding a normal form if one exists.)
+
+Preview: if the evaluation of a function has side effects, then the
+choice of an evaluation strategy will make a big difference in which
+side effect occur and in which order.
index 28fc8c4..d0d77f7 100644 (file)
@@ -36,7 +36,8 @@ Topics: Applications; Basics of Lambda Calculus; Comparing Different Languages
 
 Topics: Reduction and Convertibility; Combinators; Evaluation Strategies and Normalization; Decidability; Lists and Numbers
 
-(27 Sept) ...(Notes to come) 
+(27 Sept) Lecture notesfor [[Week3]];  [[Assignment3]].
+
 Topics: Recursion with Fixed Point Combinators
 
 <!-- Introducing the notion of a "continuation", which technique we'll now already have used a few times
index e047312..571ed7b 100644 (file)
@@ -1,3 +1,5 @@
+[[!toc]]
+
 Building Lists
 ==============
 
index d9c7f82..b39906c 100644 (file)
@@ -52,6 +52,7 @@ get more out of. (Rinse and repeat.)
 *      [Penn lambda calculator](http://www.ling.upenn.edu/lambda/) Pedagogical software developed by Lucas Champollion, Josh Tauberer and Maribel Romero.<p>
 
 <!-- Haskell Curry had ideas that he felt were validated upon reading a 1924 paper by M. Schönfinkel "Uber die Bausteine der mathematischen Logik" which used combinators in a similar way to his own ideas. Haskell then wrote "An analysis of logical substitution" which appeared in the American Journal of Mathematics in 1929. -->
+
 *      [[!wikipedia Moses Schönfinkel]]
 *      [[!wikipedia Haskell Curry]]
 *      [[!wikipedia Alonzo Church]]<p>
@@ -66,6 +67,8 @@ get more out of. (Rinse and repeat.)
        <http://people.cs.uu.nl/jeroen/article/combinat/combinat.ps>
 *      [Chris Barker's Iota and Jot](http://semarch.linguistics.fas.nyu.edu/barker/Iota/)<p>
 
+*       [To Dissect a Mockingbird](http://dkeenan.com/Lambda/index.htm)
+
 ## Evaluation Order ##
 
 *      [[!wikipedia Evaluation strategy]]
@@ -92,7 +95,7 @@ get more out of. (Rinse and repeat.)
 *      [Y Combinator for Dysfunctional Non-Schemers](http://rayfd.wordpress.com/2007/05/06/y-combinator-for-dysfunctional-non-schemers/)
 *      [The Y Combinator](http://www.ece.uc.edu/~franco/C511/html/Scheme/ycomb.html)
 *      [The Y Combinator](http://dangermouse.brynmawr.edu/cs245/ycomb_jim.html) derives the applicative-order Y-combinator from scratch, in Scheme. This derivation is similar in flavor to the derivation found in The Little Schemer, but uses a slightly different starting approach...
-
+*       [The church of the least fixed point, by Sans Pareil](http://www.springerlink.com/content/n4t2v573m58g2755/)
 
 ## Types ##
 
diff --git a/temp b/temp
deleted file mode 100644 (file)
index 46f37af..0000000
--- a/temp
+++ /dev/null
@@ -1,13 +0,0 @@
-let empty = (\f (\z z)) in
-let ml = (\h (\t (\f (\z ((f h) ((t f) z)))))) in
-let list = ((ml a) ((ml b) ((ml c) ((ml d) ((ml e) empty))))) in
-let map = (\f (\l (l (\h (\t ((ml (f h)) t)))))) in
-
-(
-
-list
-
-((map (\x x)) list)
-
-)
-
diff --git a/temp.mdwn b/temp.mdwn
deleted file mode 100644 (file)
index 585e666..0000000
--- a/temp.mdwn
+++ /dev/null
@@ -1,78 +0,0 @@
-<textarea id="INPUT" style="border: 2px solid black; color: black; font-family: monospace; height: 3in; overflow: auto; padding: 0.5em; width: 100%;">
-let true = \x y. x in
-let false = \x y. y in
-let and = \l r. l r false in
-(
-       (and true true yes no)
-       (and true false yes no)
-       (and false true yes no)
-       (and false false yes no)
-)
-</textarea>
-<input id="PARSE" value="Normalize" type="button">
-<input id="ETA" type="checkbox">do eta-reductions too
-<noscript><p>You may not see it because you have JavaScript turned off. Uffff!</p></noscript>
-<script src="/code/lambda.js"></script>
-<script src="/code/tokens.js"></script>
-<script src="/code/parse.js"></script>
-<script src="/code/json2.js"></script>
-<pre id="OUTPUT">
-</pre>
-<script>
-/*jslint evil: true */
-
-/*members create, error, message, name, prototype, stringify, toSource,
-    toString, write
-*/
-
-/*global JSON, make_parse, parse, source, tree */
-
-// Make a new object that inherits members from an existing object.
-
-if (typeof Object.create !== 'function') {
-    Object.create = function (o) {
-        function F() {}
-        F.prototype = o;
-        return new F();
-    };
-}
-
-// Transform a token object into an exception object and throw it.
-
-Object.prototype.error = function (message, t) {
-    t = t || this;
-    t.name = "SyntaxError";
-    t.message = message;
-    throw t;
-};
-
-
-(function () {
-    var parse = make_parse();
-
-    function go(source) {
-        var string, tree, expr, eta;
-        try {
-            tree = parse(source);
- //           string = JSON.stringify(tree, ['key', 'name', 'message', 'value', 'arity', 'first', 'second', 'third', 'fourth'], 4);
-                       expr = tree.handler();
-            // string = JSON.stringify(expr, ['key', 'name', 'message', 'value', 'arity', 'first', 'second', 'tag', 'variable', 'left', 'right', 'bound', 'body' ], 4);
-//                     string = expr.to_string() + "\n\n~~>\n\n";
-                       string = '';
-                       eta = document.getElementById('ETA').checked;
-                       string = string + reduce(expr, eta, false).to_string();
-        } catch (e) {
-            string = JSON.stringify(e, ['name', 'message', 'from', 'to', 'key',
-                    'value', 'arity', 'first', 'second', 'third', 'fourth'], 4);
-        }
-        document.getElementById('OUTPUT').innerHTML = string
-            .replace(/&/g, '&amp;')
-            .replace(/[<]/g, '&lt;');
-    }
-
-    document.getElementById('PARSE').onclick = function (e) {
-        go(document.getElementById('INPUT').value);
-    };
-}());
-
-</script>
index f749921..39e472b 100644 (file)
@@ -1,3 +1,12 @@
+[[!toc]]
+
+##More on evaluation strategies##
+
+Here are notes on [[evaluation order]] that make the choice of which
+lambda to reduce next the selection of a route through a network of
+links.
+
+
 ##Computing the length of a list##
 
 How could we compute the length of a list? Without worrying yet about what lambda-calculus implementation we're using for the list, the basic idea would be to define this recursively:
@@ -415,7 +424,7 @@ to *the tail* of the list we were evaluating its application to at the previous
 
 ##Fixed-point Combinators Are a Bit Intoxicating##
 
-![tatoo](/y-combinator.jpg)
+![tatoo](/y-combinator-fixed.jpg)
 
 There's a tendency for people to say "Y-combinator" to refer to fixed-point combinators generally. We'll probably fall into that usage ourselves. Speaking correctly, though, the Y-combinator is only one of many fixed-point combinators.
 
@@ -583,7 +592,9 @@ truth and circularity](http://tinyurl.com/2db62bk) for an approach
 that is similar, but expressed in terms of non-well-founded sets
 rather than recursive functions.
 
-HOWEVER, you should be cautious about feeling too comfortable with
+##However...##
+
+You should be cautious about feeling too comfortable with
 these results.  Thinking again of the truth-teller paradox, yes,
 <code>&Omega;</code> is *a* fixed point for `I`, and perhaps it has
 some a privileged status among all the fixed points for `I`, being the
diff --git a/y-combinator-fixed.jpg b/y-combinator-fixed.jpg
new file mode 100644 (file)
index 0000000..7ec5af8
Binary files /dev/null and b/y-combinator-fixed.jpg differ