The following procedure computes a mathematical function called Ackermann's function.
(define (A x y)
(cond ((= y 0) 0)
((= x 0) (* 2 y))
((= y 1) 2)
(else (A (- x 1)
(A x (- y 1))))))
What are the values of the following expressions?
(A 1 10)
(A 2 4)
(A 3 3)
Consider the following procedures, where A
is the procedure defined above:
(define (f n) (A 0 n))
(define (g n) (A 1 n))
(define (h n) (A 2 n))
(define (k n) (* 5 n n))
Give concise mathematical definitions for the functions computed by the procedures f
, g
, and h
for positive integer values of n. For example, (k n)
computes 5n2.
Ah, more substitution! What joy!
(A 1 10)
= (A (- 1 1) (A 1 (- 10 1)))
= (A 0 (A 1 9))
= (A 0 (A (- 1 1) (A 1 (- 9 1))))
= (A 0 (A 0 (A 1 8)))
= (A 0 (A 0 (A (- 1 1) (A 1 (- 8 1)))))
= (A 0 (A 0 (A 0 (A 1 7))))
= (A 0 (A 0 (A 0 (A (- 1 1) (A 1 (- 7 1))))))
= (A 0 (A 0 (A 0 (A 0 (A 1 6)))))
= (A 0 (A 0 (A 0 (A 0 (A (- 1 1) (A 1 (- 6 1)))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 5))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A (- 1 1) (A 1 (- 5 1))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 4)))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A (- 1 1) (A 1 (- 4 1)))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 3))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A (- 1 1) (A 1 (- 3 1))))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 2)))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A (- 1 1) (A 1 (- 2 1)))))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 1))))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 2)))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (* 2 2)))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 4))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (* 2 4))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 8)))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (* 2 8)))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 16))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (* 2 16))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 32)))))
= (A 0 (A 0 (A 0 (A 0 (* 2 32)))))
= (A 0 (A 0 (A 0 (A 0 64))))
= (A 0 (A 0 (A 0 (* 2 64))))
= (A 0 (A 0 (A 0 128)))
= (A 0 (A 0 (* 2 128)))
= (A 0 (A 0 256))
= (A 0 (A 0 256))
= (A 0 (* 2 256))
= (A 0 512)
= (* 2 512)
= 1024
Now let's remember that
(A 1 10)
evaluates to
1024
. It'll come in handy in a minute!
(A 2 4)
= (A (- 2 1) (A 2 (- 4 1))
= (A 1 (A 2 3))
= (A 1 (A (- 2 1) (A 2 (- 3 1))))
= (A 1 (A 1 (A 2 2)))
= (A 1 (A 1 (A (- 2 1) (A 2 (- 2 1)))))
= (A 1 (A 1 (A 1 (A 2 1))))
= (A 1 (A 1 (A 1 2)))
= (A 1 (A 1 (A (- 1 1) (A 1 (- 2 1)))))
= (A 1 (A 1 (A 0 (A 1 1))))
= (A 1 (A 1 (A 0 2)))
= (A 1 (A 1 (* 2 2)))
= (A 1 (A 1 4))
= (A 1 (A 1 4))
= (A 1 (A (- 1 1) (A 1 (- 4 1))))
= (A 1 (A 0 (A 1 3)))
= (A 1 (A 0 (A (- 1 1) (A 1 (- 3 1)))))
= (A 1 (A 0 (A 0 (A 1 2))))
= (A 1 (A 0 (A 0 (A (- 1 1) (A 1 (- 2 1))))))
= (A 1 (A 0 (A 0 (A 0 (A 1 1)))))
= (A 1 (A 0 (A 0 (A 0 2))))
= (A 1 (A 0 (A 0 (* 2 2))))
= (A 1 (A 0 (A 0 4)))
= (A 1 (A 0 (* 2 4)))
= (A 1 (A 0 8))
= (A 1 (* 2 8))
= (A 1 16)
= (A (- 1 1) (A 1 (- 16 1)))
= (A 0 (A 1 15))
= (A 0 (A (- 1 1) (A 1 (- 15 1))))
= (A 0 (A 0 (A 1 14)))
= (A 0 (A 0 (A (- 1 1) (A 1 (- 14 1)))))
= (A 0 (A 0 (A 0 (A 1 13))))
= (A 0 (A 0 (A 0 (A (- 1 1) (A 1 (- 13 1))))))
= (A 0 (A 0 (A 0 (A 0 (A 1 12)))))
= (A 0 (A 0 (A 0 (A 0 (A (- 1 1) (A 1 (- 12 1)))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 11))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A (- 1 1) (A 1 (- 11 1))))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 10)))))))
And substituting in the result from the previous evaluation gives:
= (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 1024))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 (* 2 1024))))))
= (A 0 (A 0 (A 0 (A 0 (A 0 2048)))))
= (A 0 (A 0 (A 0 (A 0 (* 2 2048)))))
= (A 0 (A 0 (A 0 (A 0 4096))))
= (A 0 (A 0 (A 0 (* 2 4096))))
= (A 0 (A 0 (A 0 8192)))
= (A 0 (A 0 (* 2 8192)))
= (A 0 (A 0 16384))
= (A 0 (* 2 16384))
= (A 0 32768)
= (* 2 32768)
= 65536
And again, it may be judicious to remember that
(A 2 4)
evaluates to
65536
...
(A 3 3)
= (A (- 3 1) (A 3 (- 3 1)))
= (A 2 (A 3 2))
= (A 2 (A (- 3 1) (A 3 (- 2 1))))
= (A 2 (A 2 (A 3 1)))
= (A 2 (A 2 2))
= (A 2 (A (- 2 1) (A 2 (- 2 1))))
= (A 2 (A 1 (A 2 1)))
= (A 2 (A 1 2))
= (A 2 (A (- 1 1) (A 1 (- 2 1))))
= (A 2 (A 0 (A 1 1)))
= (A 2 (A 0 2))
= (A 2 (* 2 2))
= (A 2 4)
= 65536
So what about the definitions of
f
,
g
and
h
?
How about if we try subsititution... We need to remember that we're to provide definitions for all positive integer values of
n. I.e.
n > 0. Here's
f
:
(f n)
= (A 0 n)
= (cond ((= n 0) 0)
((= 0 0) (* 2 n))
((= n 1) 2)
(else (A (- 0 1)
(A 0 (- n 1)))))
= (cond (#f 0)
((= 0 0) (* 2 n))
((= n 1) 2)
(else (A (- 0 1)
(A 0 (- n 1)))))
= (cond (#f 0)
(#t (* 2 n))
((= n 1) 2)
(else (A (- 0 1)
(A 0 (- n 1)))))
= (* 2 n)
So
(f n)
computes
2n
.
Now for
g
. First, let's evaluate a base case, when
n = 1.
(g 1)
= (A 1 1)
= (cond ((= 1 0) 0)
((= 1 0) (* 2 1))
((= 1 1) 2)
(else (A (- 1 1)
(A 1 (- 1 1))))))
= (cond (#f 0)
((= 1 0) (* 2 1))
((= 1 1) 2)
(else (A (- 1 1)
(A 1 (- 1 1))))))
= (cond (#f 0)
(#f (* 2 1))
((= 1 1) 2)
(else (A (- 1 1)
(A 1 (- 1 1))))))
= (cond (#f 0)
(#f (* 2 1))
(#t 2)
(else (A (- 1 1)
(A 1 (- 1 1))))))
= 2
And now for any
n > 1:
(g n)
= (A 1 n)
= (cond ((= n 0) 0)
((= 1 0) (* 2 n))
((= n 1) 2)
(else (A (- 1 1)
(A 1 (- n 1))))))
= (cond (#f 0)
((= 1 0) (* 2 n))
((= n 1) 2)
(else (A (- 1 1)
(A 1 (- n 1))))))
= (cond (#f 0)
(#f (* 2 n))
((= n 1) 2)
(else (A (- 1 1)
(A 1 (- n 1))))))
= (cond (#f 0)
(#f (* 2 n))
(#f 2)
(else (A (- 1 1)
(A 1 (- n 1))))))
= (A (- 1 1) (A 1 (- n 1)))
= (A 0 (A 1 (- n 1)))
= (* 2 (A 1 (- n 1)))
= (* 2 (g (- n 1)))
Let's stop here a minute... When
n is 1,
(g n)
computes 2, and when
n is greater than 1,
(g n)
computes 2 times
(g (- n 1))
. In order words,
(g n)
computes the result of multiplying together
n 2s, or to put it more succinctly, it computes 2
n.
Finally, let's try
h
. The base case is easy enough, as it's almost identical to that of
g
:
(h 1)
= (A 2 1)
= (cond ((= 1 0) 0)
((= 2 0) (* 2 1))
((= 1 1) 2)
(else (A (- 1 1)
(A 1 (- 2 1))))))
= (cond (#f 0)
((= 2 0) (* 2 1))
((= 1 1) 2)
(else (A (- 1 1)
(A 1 (- 2 1))))))
= (cond (#f 0)
(#f (* 2 1))
((= 1 1) 2)
(else (A (- 1 1)
(A 1 (- 2 1))))))
= (cond (#f 0)
(#f (* 2 1))
(#t 2)
(else (A (- 1 1)
(A 1 (- 2 1))))))
= 2
However, for for any
n > 1 is a "bit more tricky":
(h n)
= (A 2 n)
= (cond ((= n 0) 0)
((= 2 0) (* 2 n))
((= n 1) 2)
(else (A (- n 1)
(A n (- 2 1)))))
= (cond (#f 0)
((= 2 0) (* 2 n))
((= n 1) 2)
(else (A (- n 1)
(A n (- 2 1)))))
= (cond (#f 0)
(#f (* 2 n))
((= n 1) 2)
(else (A (- n 1)
(A n (- 2 1)))))
= (cond (#f 0)
(#f (* 2 n))
(#f 2)
(else (A (- n 1)
(A n (- 2 1)))))
= (A (- n 1) (A n (- 2 1)))
= (A (- n 1) (A n 1))
... and so on. Let's not do that.
Instead, let's try some substitutions for small values of
n. We know already that
(h 1)
is 2, so let's try with the subsequent values of
n... And you'll forgive me, I hope, if skip the step-by-step evaluations of
cond
operators...
(h 2)
= (A 2 2)
= (A (- 2 1) (A 2 (- 2 1)))
= (A 1 (A 2 1))
= (A 1 2)
= (g 2)
We know that
(g n)
computes 2
n, so
(g 2)
(and therefore
(h 2)
) computes 2
2.
(h 3)
= (A 2 3)
= (A (- 2 1) (A 2 (- 3 1)))
= (A 1 (A 2 2))
= (A 1 4))
= (g 4)
= 24
= 16
Note that we substitutute 4 for
(A 2 2)
. This comes from the evaluation of
(h 2)
above. We'll apply similar substitutions below.
(h 4)
= (A 2 4)
= (A (- 2 1) (A 2 (- 4 1)))
= (A 1 (A 2 3))
= (A 1 (g 4))
= (A 1 16)
= (g 16)
= 216
= 65536
(h 5)
= (A 2 5)
= (A (- 2 1) (A 2 (- 5 1)))
= (A 1 (A 2 4))
= (A 1 65536)
= (g 65536)
= 265536
= a very big number
Okay, I think that's enough.
(h n)
calculates 2
(h (- n 1))
, with
(h 1)
evaluating to 2. So
(h 2)
evaluates to 2
2,
(h 3)
evaluates to 2
22,
(h 4)
evaluates to 2
222 and so on. This type of iterative exponentation is known as
tetration, which thankfully has a nice concise way of being expressed:
(h n)
computes
n2.