quick note: I'm using racket scheme locally because, well, I already had it installed. Starting at the beginning of the /number games/ chapter and working through it in a semi-logical order that should make sense if you have the book in front of you. I hope.
natural numbers
we're considering only /natural numbers/
we're not dealing with negative or fractional numbers. questions like (sub1 0) are meaningless, because there is no -1 as far as we're concerned.
zero?
the zero? procedure will return #t when given the number 0, and #f when given /anything else/
(zero? 0)
adding numbers
the o+ procedure adds two natural numbers. First attempt at implementing it:
(define o+
(lambda (n m)
(cond
((zero? m) n)
(else (o+ (add1 n) (sub1 n))))))
I made a little mistake here - accidentally used n for both of the second clause, which didn't go too well.
(define o+
(lambda (n m)
(cond
((zero? m) n)
(else (o+ (add1 n) (sub1 m))))))
this one works just fine - though it doesn't match the version in the book. This works because for every m, we add one to n until m is 0. so if $m 5$ and $n 1$, then it only takes a single step:
$$ m n 1) (m (n - 1) 5 1 = (5 1) (1 - 1) $$
(define book-o+
(lambda (n m)
(cond
((zero? m) n)
(else (add1 (book-o+ n (sub1 m)))))))
the book version works like this, deferring the add1 until after the complete addition is done. Given, say, (book-o+ 5 2), expanding it out:
(cond ((zero? 2) 5 (else (add1 (book-o+ 5 (sub1 2)))))) ;; 2 isn't 0 (add1 (book-o+ 5 1)) (add1 (cond ((zero? 1) 5) (else (add1 (book-o+ 5 (sub1 1)))))) ;; 1 isn't 0 (add1 (book-o+ 5 0)) (add1 (add1 (cond ((zero? 0) 5) (else #f)))) ;; 0 is 0 (add1 (add1 5)) 7
in comparison to my version, with (o+ 5 2)
(o+ 5 2) (cond ((zero? 2) 5) (else (o+ (add1 5) (sub1 2)))) ;; 2 isn't 0 (o+ 6 1) (cond ((zero? 1) 6) (else (o+ (add1 6) (sub1 1)))) ;; 1 isn't 0 (o+ 7 0) (cond ((zero? 0) 7) (else (o+ (add1 7) (sub1 0)))) ;; 0 is 0 7
tail call recursion
This hasn't been in the book so far, but my definition for o+ allows for tail-call optimisation. I really didn't plan that, but it's there.
the book points out here that when we're writing a recursive function, we should always start with a way to end the recursion (a /base case/). This is effectively *The First Commandment (/preliminary/)][The First Commandment (/preliminary/), expanded past /null?/ as the question to tell if whatever value we're recursing over is at it's /base/ (whatever 'empty' means for this type)
The book also points out that add1 is to number what cons is to a list. It adds an extra value. Our number system starts at 0 and we have add1, which is /kind of like/ the peano numbers