(define zero '())

(define zilch? null?)

(define succ
  (lambda (x)
    (lambda () x)))

(define pred
  (lambda (x) (x)))

(define number->nat
  (lambda (k)
    (if (zero? k)
        zero
        (succ (number->nat (sub1 k))))))

(define nat->number
  (lambda (x)
    (if (zilch? x)
        0
        (add1 (nat->number (pred x))))))

(define smaller?
  (lambda (x y)
    (cond ((zilch? x) (not (zilch? y)))
          ((zilch? y) #f)
          (else
           (smaller? (pred x) (pred y))))))

;; x - 0 = x
;; x - y = (x-1) - (y-1)
(define minus
  (lambda (x y)
    (if (zilch? y)
        x
        (minus (pred x) (pred y)))))

;; x + 0 = x
;; x + y = (x+1) + (y-1)
(define plus
  (lambda (x y)
    (if (zilch? y)
        x
        (plus (succ x) (pred y)))))

;; x * 0 = 0
;; x * 1 = x
;; x * y = x*(y-1) + x
(define times
  (lambda (x y)
    (cond ((zilch? y) zero)
          ((zilch? (pred y)) x)
          (else
           (plus (times x (pred y)) x)))))

(define one (succ zero))

;; x^0 = 1
;; x^1 = x
;; x^y = x^(y-1) * x
(define power
  (lambda (x y)
    (cond ((zilch? y) one)
          ((zilch? (pred y)) x)
          (else
           (times (power x (pred y)) x)))))

;; a higher-order function which abstracts the pattern
(define ackerman
  (lambda (n)
    (if (zilch? n)
        plus
        (lambda (x y)
          (cond ((zilch? y) (pred n))
                ((zilch? (pred y)) x)
                (else
                 ((ackerman (pred n)) ((ackerman n) x (pred y)) x)))))))