Lab 8

Goal

To learn about some of the complexities of dealing with circular lists.

Experiment

The built-in procedure length works correctly on proper lists, but will go into an infinite loop on lists with a loop back. For instance, this sequence of Scheme commands will go into an infinite loop:
(define L1 '(1 2 3 4 5))
(define M (cddddr L1))
(set-cdr! M (cddr L1))
(length L1)
The resulting L1 is a structure with 5 pairs. The cars are the numbers 1 through 5. Let us identify the pairs by their cars. The mutation done by the set-cdr! makes the cdr of pair 5 be pair 3. Thus when length "walks down" L1 it visits the pairs in the order
1, 2, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, ....
As a result, length never terminates. L1 consists of an initial segment 1, 2 followed by a circle 3, 4, 5. Write a proceduure clength that takes an arbitrary list structure and returns its length if it is a list without loop back. If there is a loop back, clength returns a list of two numbers (m n) where m is the number of pairs in the initial segment of the input and n is the number of pairs in the circle caused by the loop back. For the list structure L1 above, (clength L1) returns the list (2 3). Submit your definition to the Automated Tester. Be sure that the procedure that you submit has been named clength. No other name will be accepted.

Hints

First write a definition for clength that just computes the length of an ordinary list using an auxiliary procedure that runs as an iterative process. Then modify your auxiliary procedure to maintain a list of the pairs that have been seen already as it walks down the original list. You may use memq to test for membership on a list or write your own function using eq?. Do not use equal? or member (which uses equal?). If two of the cars of pairs in the input list have similar list structures that are themselves circular lists, equal? will never terminate. You may use length if you wish but be certain that the list you apply it to is guaranteed not to contain a loop back. (The input list might; that is why we are writing clength in the first place.)

Be sure that your auxiliary procedure maintains a list of seen pairs, not a list of seen list elements. Does your clength work correctly on list structures L2 and L3 below?

(define L2 '(a a a a a))
(define M2 (cddddr L2))
(set-cdr! M2 (cddr L2))

(define L3 '(1 2))
(set-cdr! (cdr L3) L3)
It is possible to write clength without maintaining a list of seen pairs, but the code is more complicated, partly because you can't take advantage of some of the procedures already defined in Scheme.