Indefinite recursion

One of the familiar patterns for recursive procedures is numerical recursion, with zero (or sometimes one) as the base case:

(define power
  (lambda (base exponent)
    (if (zero? exponent)
        1
        (* base (power base (- exponent 1))))))

Another is structural recursion on lists, with an empty list (or sometimes a one-element list) as the base case:

(define sum-of-list
  (lambda (ls)
    (if (null? ls)
        0
        (+ (car ls) (sum-of-list (cdr ls))))))

In both of these patterns, it is possible to forecast the number of recursive calls that will be made before the base case is reached: In a numerical recursion, the value of the parameter that is decremented toward zero indicates the number of recursive calls remaining, and in a structural recursion the number of recursive calls is the same as the length of the list.

Sometimes, however, the recursion is indefinite, in the sense the number of recursive calls needed to establish the condition that terminates the recursion is not apparent. For instance, here is a recursive procedure that finds and returns the least prime divisor of any integer greater than or equal to 2:

(define least-prime-divisor
  (lambda (num)
    (if (or (not (integer? num))
            (< num 2))
        (error 'least-prime divisor
               "The argument must be an integer greater than or equal to 2"))
    (if (even? num)
        2
        (least-prime-divisor-kernel num 3))))

(define least-prime-divisor-kernel
  (lambda (num trial-divisor)
    (if (zero? (remainder num trial-divisor))
        trial-divisor
        (least-prime-divisor-kernel num (+ trial-divisor 2)))))

The husk procedure checks the precondition and, if it is met, also checks whether num is even; since 2 is the least prime number, it should be returned whenever num is divisible by 2, that is, whenever num is even. In all other cases, the kernel procedure is called, with 3 as the first trial divisor; the kernel procedure continues to check odd trial divisors (3, 5, 7, and so on) in ascending order until it comes up with one that evenly divides num. This must happen eventually; num is divisible at least by itself, so that when trial-divisor becomes equal to num the procedure will terminate. But if num is large it may be difficult for the programmer to predict how many times the kernel procedure will invoke itself before terminating.


Exercise 1

Use trace-define to find out how many recursive calls are needed when num is 1007, and how many are needed when num is 1009.


There are cases in which it is easy to write an indefinite recursion, but difficult to prove that it will always terminate. The following procedure illustrates the problem: Given any positive integer, it constructs and returns a sequence of integers in which each even number n is followed by n/2 and each odd number n, except 1, is followed by 3n + 1:

(define Collatz
  (lambda (num)
    (cond ((= num 1) '(1))
          ((even? num) (cons num (Collatz (quotient num 2))))
          (else (cons num (Collatz (+ (* 3 num) 1)))))))

Exercise 2

Call this procedure to construct the sequence that begins with the number 29, and confirm that every element in the sequence is generated according to the rule described above. Then call the procedure to construct the sequence that begins with the number 27.


The interesting point about the Collatz procedure is that in spite of the fact that it is easily defined and contains no difficult mathematical functions, no one knows whether it always terminates. Perhaps there is a value for num that begins a sequence that never reaches 1 and hence never ends.

In real-world programming, we generally try to avoid procedures that are not known to terminate.


Exercise 3

Consider a leaf-transformation procedure, like incremeent-every-leaf from the lab on trees. Can we prove that all of the recursive calls to that procedure will eventually terminate? If so, how?


Exercise 4

Catch up on any of the exercises from previous labs that you haven't previously done. If you're all caught up, try exercises 4.8 - 4.11 on pages 114 and 115 of the textbook.

This document is available on the World Wide Web as

http://www.math.grin.edu/~stone/courses/scheme/indefinite-recursion.html

created February 22, 1998
last revised May 31, 1998

John David Stone (stone@math.grin.edu)