X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=blobdiff_plain;f=arithmetic.mdwn;h=289b28438916da6ca8a35ff9d23b34e772e43177;hp=dd59863ebc0e5e0cc57c39095a2b50ec779745d5;hb=e1860468dc97e6249ecd19e96a2e7fffe9430d0e;hpb=14458e59f4e02fa020bc26a30512cbfa35eec2e2 diff --git a/arithmetic.mdwn b/arithmetic.mdwn index dd59863e..289b2843 100644 --- a/arithmetic.mdwn +++ b/arithmetic.mdwn @@ -1,3 +1,16 @@ +Here are a bunch of pre-tested operations for the untyped lambda calculus. In some cases multiple versions are offered. + +Some of these are drawn from: + +* [[!wikipedia Lambda calculus]] +* [[!wikipedia Church encoding]] +* Oleg's [Basic Lambda Calculus Terms](http://okmij.org/ftp/Computation/lambda-calc.html#basic) + +and all sorts of other places. Others of them are our own handiwork. + + +**Spoilers!** Below you'll find implementations of map and filter for v3 lists, and several implementations of leq for Church numerals. Those were all requested in Assignment 2; so if you haven't done that yet, you should try to figure them out on your own. (You can find implementations of these all over the internet, if you look for them, so these are no great secret. In fact, we'll be delighted if you're interested enough in the problem to try to think through alternative implementations.) + ; booleans let true = \y n. y in ; aka K @@ -21,12 +34,62 @@ let make_triple = \x y z f. f x y z in - ; Church numerals + ; 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 @@ -38,6 +101,7 @@ ; 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) @@ -62,25 +126,7 @@ let eq = \m n. and (leq m n) (leq n m) in ; or - ; more 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 - - - ; more efficient comparisons, Oleg's gt provided some simplification + ; 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) @@ -100,6 +146,7 @@ ; 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: @@ -122,9 +169,11 @@ ; 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: @@ -162,9 +211,11 @@ 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: @@ -178,39 +229,20 @@ (make_triple cur false sofar) ; enough )) in - ; Curry's fixed point combinator + + ; Rosenbloom's fixed point combinator let Y = \f. (\h. f (h h)) (\h. f (h h)) in ; Turing's fixed point combinator - let Z = (\u f. f (u u f)) (\u f. f (u u f)) in - - + let Theta = (\u f. f (u u f)) (\u f. f (u u f)) 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 = \lst. (\shift lst. lst shift (make_pair empty junk) 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) zero 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 - - - ; 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 error (lst get_2nd get_1st) in - let tail_empty = empty in - let tail = \lst. isempty lst tail_empty (lst get_2nd get_2nd) in - + ; length for version 1 lists let length = Y (\self lst. isempty lst 0 (succ (self (tail lst)))) in + true + + + + + +