We talked about recursion earlier. Recursion is really a substitute for a loop. When you solve a problem that seems to need some kind of repetition, you can choose either to use recursion or to use a loop. (Do not try to use both!)
Now that you have seen loops, you are probably tempted to use them for all repetition. The reason is that they are more like how you are accustomed to thinking about repetition. But let's compare definitions of isSubstring, one using a loop, the other using recursion. Here is the loop version that is simplified by using isPrefix.
Define isSubstring(needle: String, haystack: String): Boolean by isSubstring(needle, haystack) = found | Let needleLen = length(needle). Let haystackLen = length(haystack). Let i = 1. Let found = false. While (not found) and (i <= haystackLen - needleLen + 1) do If needle == haystack_*[i,..., i + needleLen - 1]) then Relet found = true. %If Relet i = i + 1. %While %DefineHere is a recursive definition of the same function.
Define isSubstring(needle: String, haystack: String): Boolean by case isSubstring(s, t) = true when isPrefix(s, t) case isSubstring(s, t) = false when t == "" case isSubstring(s, t) = isSubstring(s, tail(t)) %DefineThe recursive definition is shorter. It also has the advantage that you can look at each case separately, and ask whether it makes sense (in the last case under the presumption that the recursive use of isSubstring works correctly). You do not need to hold everything up at once.
Experience has shown that defining functions by recursion often takes less of your time. With experience, you get correct definitions more quickly than with a loop, often requiring no debugging at all.
[solve] Using a loop, and not recursion,, define function sumOdds(n) = 1 + 3 + ... + n. For example, sumOdds(5) = 1 + 3 + 5 = 9. Assume that n is odd.
Add an Execute part that computes sumOdds(n) for n = 1, 3, 5, ..., 25.
[solve] Using a recursion, and not a loop,, define function sumOdds(n) = 1 + 3 + ... + n. For example, sumOdds(5) = 1 + 3 + 5 = 9. Assume that n is odd.
Add an Execute part that computes sumOdds(n) for n = 1, 3, 5, ..., 25.
[solve] Using a loop (and not recursion), define a function isPrime(n) that tells whether a given positive integer n is prime. Write Add your own Execute part that performs a few tests.
[solve] Using recursion (and not a loop), define function anyFactor(n,i,j), which yields true if one of the numbers i, i+1, ... j is a factor of n. (More precisely, it returns true if there is a factor k of n where i ≤ k ≤ j.)
After defining anyFactor, define isPrime as by saying that n is prime is it does not have any factor from 2 to n-1. Add an Execute part that does some tests of isPrime.
Hint.
anyFactor(n,i,j) is always false when i > j, because then there are no numbers k at all that satisfy i < k ≤ j, let alone any that are factors of n.
Otherwise, if i is a factor of n, then there certainly is a factor of n in that range.
What should you do in the case where i ≤ j and i is not a factor of n?
Recursion is a substitute for a loop. You can typically solve a given algorithmic problem either using recursion or using a loop.
Although beginning programmers tend to select loops for their algorithms, experts have found that selecting recursion often takes less time, results in a shorter and more elegant program, and works surprisingly often without any debugging. Recursion also allows you to think about each case in an algorithm separately without the need to hold everything up in the air at once.
Some loops (and recursive function definitions) go through a sequence of values accumulating a result. They need to look at all of the value in the sequence, no matter what. For example, to add up some values, you need to look at them all.
Some loops (and recursive function definitions) go through a sequence of values looking for one that has a desired property. Those algorithms can stop as soon as they have found what they are looking for. If they go through the entire sequence without finding what they are looking for, they need to do something appropriate.
Sometimes, a search algorithm is looking for a value that does not have a given property. For example, to ask whether two strings are the same, you look for an index where they have different characters.