?so /usr/aaron/demos/start.demo
?he 'RECURSION2''Page %   '
.sp 2
.ce 2
RECURSION and REPETITION
========= === ==========

In several of the demos and mini-projects, you will find that we define
procedures in terms of themselves, that is recursively. This is because
there are many programming tasks which are achieved fairly simply
with the aid of recursion, and which would be much harder to do by other
means.

The last part of the Edinburgh lecture notes on Artificial
Intelligence includes a section (pages P.28 to P.45) on the "little man" model of
program-execution, and if you read this it may help you to understand how
recursion works. However, it is possible to learn to use it without having
any explicit model. You can get an intuitive grasp of it from doing lots
of exercises.

Here are a few exercises to help you get used to recursive programs
involving numbers. The other demos will give you lots of practice with
recursion on lists.

.in +3
.ti -3
1. One of the functions in the TURTLE demo was intended to
draw a square.
.tp 6
 	: FUNCTION SQUARE (SIDE);
 	:	REPEAT 4 TIMES
 	:		DRAW(SIDE);
 	:		TURN(90);
 	:	CLOSE;
 	: END;
.br

This used the "schema"
 	 REPEAT <number> TIMES <action> CLOSE;

Suppose we wanted to make a slightly more general function, which,
instead of drawing only four times could draw a number of lines determined
by an argument, and which, instead of always turning through ninety
degrees would also turn through an amount specified by an argument. We could
again use the REPEAT construction, thus:
.tp 6
 	: FUNCTION POLYGON (SIDE, ANGLE, NUMBER);
 	:	REPEAT NUMBER TIMES
 	:		DRAW(SIDE);
 	:		TURN(ANGLE);
 	:	CLOSE;
 	: END;
.br

How would you define SQUARE in terms of this function?
.tp 3
 	: FUNCTION SQUARE (SIDE);
 	:	POLYGON(....., ....., .....)
 	: END;
.br

Complete this definition and try it out.

Instead of using REPEAT we can use recursion to define the function
POLYGON.
The "schema" for this is:
.tp 7
 	: FUNCTION POLYGON (SIDE, ANGLE, NUMBER);
 	:	IF <not yet finished>
 	:	THEN
 	:		<draw one side and turn>
 	:		<restart with NUMBER reduced>
 	:	CLOSE;
 	: END;

Can you replace the bits of English with POP11?

<not yet finished> should be replaced by a test whether there
are still some lines to be drawn, i.e. a test whether NUMBER is
bigger than 0.

<draw one side and turn> should be replaced by commands using
DRAW and TURN, with appropriate arguments.

<restart with NUMBER reduced> requires a call of POLYGON, i.e. the
function being defined, with NUMBER-1 as its last argument,
and the remaining two arguments unaltered. Notice that the
recursive call must include as many arguments as the function
being defined has formal parameters (in this case three).

Test your definition of POLYGON when you've completed it.
Try drawing an octagon with it.

.ti -3
2. In the TURTLE demo you were introduced to a function SQUIRAL
which went something like this:
.tp 7
 	: FUNCTION SQUIRAL (NUMBER, DISTANCE, SUBTRACT);
 	:	REPEAT NUMBER TIMES
 	:		DRAW(DISTANCE);
 	:		TURN(90);
 	:		DISTANCE - SUBTRACT ->DISTANCE;
 	:	CLOSE
 	: END;
.br

The use of "REPEAT"......."CLOSE" makes it easy to get a program
to do something a specified number of times. But how is this achieved? Could
you write a program like squiral without using REPEAT?
(If you think you can, then try it before reading on).

Here is one way of thinking about SQUIRAL. We want to do something
a specified number of times, i.e. NUMBER times.
There are two main cases to consider. (a) NUMBER is greater than 0,
i.e. you still have to perform the action. (b) NUMBER is 0, i.e.
there's nothing more to be done (doing something 0 times is the same as not
doing it!).
Why should we consider case (b) at all? The answer is that it is helpful
do deal with case (a) in such a way that you do the action once, then
reduce NUMBER by 1, and start again. So although you never ask for the action
to be performed zero times, the program will eventually get down to a zero
value for NUMBER.

We thus have the following "schema" for the program:
.tp 7
 	: FUNCTION SQUIRAL(NUMBER,  DISTANCE, SUBTRACT);
 	:  IF	NUMBER > 0
 	:  THEN
 	:  	<DO THE ACTION>
 	:  	<CALL SQUIRAL AGAIN WITH NUMBER REDUCED BY 1>
 	:  CLOSE
 	: END;
.br

where the action is:
.tp 2
 	: DRAW(DISTANCE);
 	: TURN(90);

Problem: what will this do when NUMBER is 0?

In the original version of SQUIRAL we also included an instruction
to reduce the value of DISTANCE by the amount specified in
SUBTRACT. Now instead of doing that as part of the "action",
we can simply give an appropriate second argument to our recursive call
of SQUIRAL, i.e. DISTANCE - SUBTRACT instead of
DISTANCE. So the recursive call looks like this:

 	:	SQUIRAL(NUMBER-1, DISTANCE-SUBTRACT, SUBTRACT)
.br

i.e. start SQUIRAL again with NUMBER reduced by 1, with
DISTANCE reduced by SUBTRACT and with the same value for
SUBTRACT as before.

Complete this version of SQUIRAL and try it out.

.ti -3
3. One reason why this method is perhaps preferable, is that you can now
easily modify the definition of SQUIRAL so that it has a more complex
stopping condition.
The last version of SQUIRAL stopped as soon as NUMBER had the value 0.
More precisely, it continued drawing so long as the value of NUMBER was
greater than 0. Suppose you want to make the program continue drawing
until the turtle reaches a a position where its X-coordinate is
between 10 and 15. You can do this simply by changing
what comes between IF and THEN:

.tp 3
 	:	IF	XPOSITION < 10
 	:		OR	15 < XPOSITION
 	:	THEN
.br

Alternatively you may wish to combine the new continuation
condition with the old one, so that the drawing stops
if either NUMBER gets down to 0 or the turtle gets to a certain range
of locations. Suppose the picture has size 21 by 21. Redefine
SQUIRAL so that drawing stops if ever the turtle gets to within
two steps from the centre of the picture (the position [11 11]), or NUMBER gets down to
zero.
You will probably find it helpful to use the function ABS.
To find out whether YPOSITION differs from 11 by more than 2 you can
use the test
 	ABS(YPOSITION - 11) > 2

The new defition will start:
 	: FUNCTION SQUIRAL (NUMBER, DISTANCE, SUBTRACT);
 	:	IF	NUMBER > 0
 	:		AND	....
.br

Can you complete it?
