X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=blobdiff_plain;f=lambda_library.mdwn;h=e170dcf424d4b775d16faf24657e32d37502a6be;hp=bdd016875c302e314ae06f632183fd62937c7f19;hb=7b80daef951f850ecab4e539d103607c7808d73b;hpb=c675006fcaa7ef7f096b0cf8e73e28ecb79aa1a9 diff --git a/lambda_library.mdwn b/lambda_library.mdwn index bdd01687..e170dcf4 100644 --- a/lambda_library.mdwn +++ b/lambda_library.mdwn @@ -12,7 +12,7 @@ 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 + ;; 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 @@ -25,71 +25,20 @@ and all sorts of other places. Others of them are our own handiwork. let iff = \p q. not (xor p q) in ; or let iff = \p q. p q (not q) in - ; pairs + ;; tuples let make_pair = \x y f. f x y in let get_fst = \x y. x in ; aka true let get_snd = \x y. y in ; aka false - - ; triples let make_triple = \x y z f. f x y z in - ; Church numerals: basic operations - + ;; Church numerals 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_snd) - ; 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_fst in - let head = \lst. isempty lst err (lst get_snd get_fst) in - let tail_empty = empty in - let tail = \lst. isempty lst tail_empty (lst get_snd get_snd) 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 @@ -101,7 +50,6 @@ and all sorts of other places. Others of them are our own handiwork. ; 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_snd) @@ -119,13 +67,11 @@ and all sorts of other places. Others of them are our own handiwork. ; 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_fst) ; where base is @@ -145,7 +91,7 @@ and all sorts of other places. Others of them are our own handiwork. (\p. make_pair false (K p)) ; and consume is (\p. p get_snd p) in - + ; -n is a fixedpoint of \x. add (add n x) x ; but unfortunately Y that_function doesn't normalize @@ -170,8 +116,8 @@ and all sorts of other places. Others of them are our own handiwork. (\p. p get_snd p) in - let min = \m n. sub m (sub m n) in - let max = \m n. add n (sub m n) 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 @@ -206,8 +152,7 @@ and all sorts of other places. Others of them are our own handiwork. ; 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 + (\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_fst in let mod = \n d. divmod n d get_snd in @@ -230,19 +175,134 @@ and all sorts of other places. Others of them are our own handiwork. )) in - ; Rosenbloom's fixed point combinator - let Y = \f. (\h. f (h h)) (\h. f (h h)) in - ; Turing's fixed point combinator + ;; fixed point combinators + ; Curry/Rosenbloom's + let Y = \f. (\h. f (h h)) (\h. f (h h)) in + ; Turing's let Theta = (\u f. f (u u f)) (\u f. f (u u f)) in ; now you can search for primes, do encryption :-) - let gcd = Y (\gcd m n. iszero n m (gcd n (mod m n))) in - let lcm = \m n. or (iszero m) (iszero n) 0 (mul (div m (gcd m n)) n) in + let gcd = Y (\gcd m n. iszero n m (gcd n (mod m n))) in ; or + let gcd = \m n. iszero m n (Y (\gcd m n. iszero n m (lt n m (gcd (sub m n) n) (gcd m (sub n m)))) m n) in + let lcm = \m n. or (iszero m) (iszero n) 0 (mul (div m (gcd m n)) n) 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_fst in + let head = \lst. isempty lst err (lst get_snd get_fst) in + let tail_empty = empty in + let tail = \lst. isempty lst tail_empty (lst get_snd get_snd) in + + let length = Y (\length lst. isempty lst 0 (succ (length (tail lst)))) in + let fold = Y (\fold lst f z. isempty lst z (f (head lst) (fold (tail lst) f z))) in + let map = \f. Y (\map lst. isempty lst empty (make_list (f (head lst)) (map (tail lst)))) in + let filter = \f. Y (\filter lst. isempty lst empty (f (head lst) (make_list (head lst)) I (filter (tail lst)))) in + + + ;; version 3 (right-fold) 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) err in + let tail_empty = empty in + let tail = \lst. (\shift. lst shift (make_pair empty tail_empty) get_snd) + ; 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 revappend, reverse + ; revappend [a;b;c] [x;y] ~~> [c;b;a;x;y] + ; make_left_list a (make_left_list b (make_left_list c empty)) ~~> \f z. f c (f b (f a z)) + let revappend = (\make_left_lst left right. left make_left_list right) (\h t f z. t f (f h z)) in + ; from Oleg, of course it's the most elegant + let revappend = \left. left (\hd sofar. \right. sofar (make_list hd right)) I in + let rev = \lst. revappend lst empty 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 + + + ;; left-fold lists + let make_list = \h t f z. t f (f h z) in + let head = \lst. lst (\h sofar. (K (sofar (K h))) ) (\k. k err) I in + let tail = \lst. (\shift. lst shift (\a b. a tail_empty) I I) + (\h p. p (\j a b. b empty) (\t a b. b (\f z. f h (t f z))) ) in + + + ;; version 5 (CPS right-fold) lists + ; [] is \f z c a. c z + ; [1] is \f z c a. f 1 z c a + ; [1;2] is \f z c a. f 2 z (\z. f 1 z c a) a + ; [1;2;3] is \f z c a. f 3 z (\z. f 2 z (\z. f 1 z c a) a) a + let empty = \f2 z continue_handler abort_handler. continue_handler z in + let isempty = \lst larger_computation. lst + ; here's our f2 + (\hd sofar continue_handler abort_handler. abort_handler false) + ; here's our z + true + ; here's the continue_handler for the leftmost application of f2 + larger_computation + ; here's the abort_handler + larger_computation in + let make_list = \h t. \f2 z continue_handler abort_handler. + t f2 z (\sofar. f2 h sofar continue_handler abort_handler) abort_handler in + let head = \lst larger_computation. lst + ; here's our f2 + (\hd sofar continue_handler abort_handler. continue_handler hd) + ; here's our z + err + ; here are our continue_handler and abort_handler + larger_computation unused in + let tail_empty = empty in + let tail = \lst larger_computation. lst + ; here's our f2 + (\h sofar continue_handler abort_handler. continue_handler (sofar (\t y. make_pair (make_list h t) t))) + ; here's our z + (make_pair empty tail_empty) + ; here are our continue_handler and abort_handler + (\sofar. sofar (\x y. larger_computation y)) unused in + + ;; CPS left-fold lists + ; [] is \f z c a. c z + ; [1] is \f z c a. f 1 z (\z. c z) a + ; [1;2] is \f z c a. f 1 z (\z. f 2 z (\z. c z) a) a + ; [1;2;3] is \f z c a. f 1 z (\z. f 2 z (\z. f 3 z (\z. c z) a) a) a + let make_right_list = make_list in + let make_list = \h t. \f2 z continue_handler abort_handler. + f2 h z (\z. t f2 z continue_handler abort_handler) abort_handler in + let head = \lst larger_computation. lst + ; here's our f2 + (\hd sofar continue_handler abort_handler. abort_handler hd) + ; here's our z + err + ; here are our continue_handler and abort_handler + larger_computation larger_computation in + let tail = \lst larger_computation. lst + ; here's our f2 + (\h sofar continue_handler abort_handler. continue_handler (sofar (\j a b. b empty) (\t a b. b (make_right_list h t)) ) ) + ; here's our z + (\a b. a tail_empty) + ; here are our continue_handler and abort_handler + (\sofar. sofar larger_computation larger_computation) unused in - ; length for version 1 lists - let length = Y (\self lst. isempty lst 0 (succ (self (tail lst)))) in true @@ -271,7 +331,7 @@ and all sorts of other places. Others of them are our own handiwork. (\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_snd p) in - let lt = \m n. not (leq n m) 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))) @@ -324,5 +384,9 @@ let list_equal = ) ; when fold is finished, check sofar-pair (\might_be_equal right_tail. and might_be_equal (isempty right_tail)) + +; most elegant +let list_equal = \left. left (\hd sofar. \right. and (and (not (isempty right)) (eq hd (head right))) (sofar (tail right))) isempty + -->