An Illustrated Guide to "repeat"
(define (repeat fn n)
(if (= n 0) (lambda (x) x)
(compose fn (repeat fn (- n 1)))))
(define (compose f g)
(lambda (x) (f (g x))))
How on earth does this work? What happens if we call (repeat square
3) ?
First, let's use this picture to represent functions like "square" or
"first":
Now, let's see what "(compose square first)" looks like:
WAIT! But why is "square" on the bottom?
(compose square first) is
(lambda (x) (square (first x)))
The square appears first!!
This is because Scheme evaluates INSIDE OUT. The first procedure call
evaluated is (first x) because it is most inside. "square" is outside
of "(first x)" so it gets called second.
So, the input x first goes through the function "first", then it goes
through the function "square"
Let's also introduce the identity function (lambda (x) x), which
doesn't do anything to the argument, so it's just a pipe. But we'll
still think of it as a machine.
Ok, so if we call (repeat square 1), we compose square with the
identity function and get:
Notice that (repeat square 1) is the machine in the picture. The
machine "repeat" is NOT IN THE PICTURE. In fact, you can think of "repeat" as a mechanic who is making all the machines that we see.
Since we are composing two machines, you might think the Scheme code
is:
(lambda (x)
(square (lambda (y) y)))
NO! In that WRONG code, you're feeding the machine (lambda (y) y) into
the machine "square"! That is the WRONG way to connect machines in
Scheme.
The RIGHT way:
(lambda (x)
(square ( (lambda (y) y) x ) ) )
REMEMBER! You can't read Scheme code from left to right! You have to
read it INSIDE OUT.
Alright, what if we have (repeat square 2) then? Try mentally
picturing this yourself. Does it look like this?
Do you see that if you feed 4 into the (repeat square 2) machine, you
square 4 twice?
What about (repeat square 3)?
So what about (repeat square n) for some general n?
Where we kept the (repeat square (- n 1)) machine closed. If we open
up the (repeat square (- n 1)) machine, we will see many many machines
connected together just as before.
So, here is a question to test your understanding:
How many procedure are there TOTAL in when we call (repeat square n) ?
ONE LAST IMPORTANT WORD:
here, we treated the machine (repeat square n) as if its name is just
"(repeat square n)". In fact, "repeat" is a machinist THAT CREATES
MACHINES! So more accurately, we should say
(repeat square n) is the machine that's created by calling "repeat"
Hope that was helpful.
-min