SICP 2.6: Church Numerals (2011)
jlongster.com
jlongster.com
For a real challenge, try to implement the decrement function. Legend has it, Rosser thought of the solution while on the dentist's chair. (It is a bit heavier on code than the other Church numeral functions, but conceptually simple - and was a creative idea at the time, before functional programming had really come into being.)
┬──────────
┼─────┬────
┼─────┼─┬──
│ ──┬─┼ ┼ ┬
│ ┬─┼─┼ │ │
│ │ ├─┘ │ │
│ ├─┘ │ │
└─┤ │ │
└─────┤ │
└─┘
makes for an artistic picture... ((λ (f) ((λ (g) (g g)) (λ (h) (λ (x) ((f (h h)) x)))))
(λ (f)
(λ (n)
(if ((λ (p a b) (p a b)) ((λ (n) (n (λ (x) (λ (x y) y)) (λ (x y) x))) n) t nil)
((λ (n) (λ (f x) (f (n f x)))) (λ (f x) x))
((λ (m n) (m ((λ (m n) (λ (f x) (m f (n f x)))) n) (λ (f x) x)))
n (f ((λ (n) (λ (f x) (n (λ (g h) (h (g f))) (λ (u) x) (λ (u) u)))) n)))))))
Note the use of the Y combinator to implement recursion :-)Here it is in action computing the factorial of 6:
? (((λ (f) ((λ (g) (g g)) (λ (h) (λ (x) ((f (h h)) x)))))
(λ (f)
(λ (n)
(if ((λ (p a b) (p a b)) ((λ (n) (n (λ (x) (λ (x y) y)) (λ (x y) x))) n) t nil)
((λ (n) (λ (f x) (f (n f x)))) (λ (f x) x))
((λ (m n) (m ((λ (m n) (λ (f x) (m f (n f x)))) n) (λ (f x) x)))
n (f ((λ (n) (λ (f x) (n (λ (g h) (h (g f))) (λ (u) x) (λ (u) u)))) n)))))))
((λ (n) (λ (f x) (f (n f x))))
((λ (n) (λ (f x) (f (n f x))))
((λ (n) (λ (f x) (f (n f x))))
((λ (n) (λ (f x) (f (n f x))))
((λ (n) (λ (f x) (f (n f x))))
((λ (n) (λ (f x) (f (n f x))))
(λ (f x) x))))))))
#<COMPILED-LEXICAL-CLOSURE #x30200105130F>
? (funcall * '1+ 0)
720Hint: consider a function that maps the pair <n,n!> to <(n+1),(n+1)!> ...
┬──────────────────────
│ ┬────────────── ─ ┬ ┬
│ ┼─┬───────┬──── ┬ │ │
│ ┼─┼───────┼─┬── │ │ │
│ │ ┼─┬─┬── ┼─┼─┬ │ │ │
│ │ ┼─┼─┼─┬ │ ├─┘ │ │ │
│ │ └─┤ ├─┘ ├─┘ │ │ │
│ │ ├─┘ │ │ │ │
│ └───┤ │ │ │ │
│ ├─────┘ │ │ │
└─────┤ │ │ │
└───────────┤ │ │
└─┤ │
└─┘Btw, here's an even shorter version of factorial:
┬────────────────
┼─────────────┬──
│ ──┬──────── ┼ ┬
│ ┬─┼─┬────── │ │
│ │ │ ┼─┬─┬── │ │
│ │ │ ┼─┼─┼─┬ │ │
│ │ │ └─┤ ├─┘ │ │
│ │ │ ├─┘ │ │
│ │ ├───┘ │ │
│ ├─┘ │ │
└─┤ │ │
└───────────┤ │
└─┘
In de-Bruijn notation it is \\2 (\\1 (2 (\\3 2 (2 1)))) (\2) (\1), which in conventional notation is \n\f.n (\x\m.m (x (\a\b.m a (a b)))) (\x.f) (\x.x)What's amazing is that I feel like I didn't fully "get" a large portion of the book. I could work through it again in a few years and learn something from every page.
[0]Other books come close, but the impact of this book will stay with me forever.
(define (multiply number1 number2)
(lambda (f)
(number1 (lambda (x) ((number2 f) x)))))
(define (exponentiate base exponent)
(exponent base))If you look at the input and output of thrice, it looks like this:
(function that gets applied once) -> (function that gets applied 3 times)
What if we used the output as the input again? (function that gets applied once) -> (function that gets applied 3 times) -> (function that gets applied 9 times)
We have a name for what we just did to the "thrice" function, and that name is "twice". So that's (twice thrice), and we can see it makes something happen 3^2 = 9 times.See http://en.wikipedia.org/wiki/Set-theoretic_definition_of_nat...
I came just after 2.5 which was already an awesome magic trick.