================================================================== Hunk H starts here:
==================================================================
Suppose we want to sum a list of numbers.
We can write a procedure list-sumto do that, like this: Scheme> (define (list-sum lis)
(if (null? lis) if empty list? 0 then sum is zero
(+ (car lis) else it's car plus the
(list-sum (cdr lis))))) sum of rest of list #void
Try typing in this example, or cutting and pasting it from this le into your running Scheme system. (If you're reading this in a web browser, that should be easy|just cut the text from the
browser window, and paste it into your Scheme window at the prompt.) Cutting and pasting is a lot easier than typing in the whole thing!
This procedure accepts one argument,lis, which should be a list. It checks to see whether the
list is empty, i.e., a null pointer, using the predicate null?. If so, it returns 0 as the sum of the
elements in the list.
If the list is not empty, the sum of the elements is the sum of thecarvalue, plus the sum of the
elements in the rest of the list. In that case, list-sum takes the car of the list and thelist-sum
of the rest of the list, adds them together, and returns the result. Try calling this procedure with some lists of numbers, e.g.,
Scheme>(list-sum '(1 2 3)) 6
Scheme>(list-sum '(4 5 6)) 15
Scheme>(list-sum (cons 1 (cons 2 (cons 3 '())))) 6
The addition procedure +works with oating-point numbers, not just integers, so we can call
list-sum with a list of oats as well as integers. (As in most languages, oating point numbers are written with a period to represent the decimal point. Note that there is no space between the digits and the decimal point, so that Scheme won't confuse this with dot notation for lists.)
Scheme>(list-sum '(1 2.2 3.3))
We can modifylist-sumto print out its argument at each call. Then we can watch the recursion: Scheme> (define (list-sum lis)
(display "in list-sum, lis is: ") (display lis)
(newline) write a linebreak (if (null? lis) if empty list?
0 then sum is zero
(+ (car lis) else it's car plus the
(list-sum (cdr lis))))) sum of rest of list #void
3.2.1 Using Type Predicates
We can generalize the procedure tree-sum to give us the sum of nested lists of integers. The
routine pair-tree-sum will take a list of integers, or a list of lists of integers, or a mixed list of
such lists, and return the sum of all of the integers in the nested lists at any level.
pair-tree-sum will handle improper lists as well as proper ones it's easier that way.
We call this pair-tree-sumbecause we're really using nested lists as a binary tree of integers.
(Remember that a Scheme list is just a binary tree, where we're usually think of \down and to the right" as \next" in a linear list. In this case, we're going to go down and to the left as well, to compute the sum of nested lists.
In this case, the sum of a pair-tree is 0 if the pair tree is '(), and if it's a pair, the sum of the whole tree is the sum of its left subtree plus the sum of its right subtree.
Our recursive procedure will have to deal with three cases:
null lists, e.g., when it's called on the cdr of the last pair in a list integers, e.g., when it's called on the car of a list of integers, and
pairs, e.g., when it's called on the car of a list whose car is another list (i.e., a sublist), or when
it's called on the cdr of a list that's not the end of a list.
If we view a list as a binary tree of pairs, the rst two cases are the leaves of the tree|either a number, or a null child pointer.
The third case is the recursive case, where we have a subtree to sum.
Our procedure will work for improper lists as well as proper lists, because we'll treat the car and the cdr the same way, as \left child" and \right child" pointers of a tree.
Scheme>(define (pair-tree-sum pair-tree) (cond ((null? pair-tree)
0)
((number? pair-tree) pair-tree)
(else
(+ (pair-tree-sum (car pair-tree)) (pair-tree-sum (cdr pair-tree))))))
Try this out, at make sure you understand why it works.
Scheme>(pair-tree-sum '()) 0 Scheme>(pair-tree-sum 1) 1 Scheme>(pair-tree-sum '(1 . 2)) 3 Scheme>(pair-tree-sum '(1 2)) 3 Scheme>(pair-tree-sum '((1 2) 3)) 6 Scheme>(pair-tree-sum '((40 . 30) . (20 . 10))) 100 Scheme>(pair-tree-sum '((40 30) (20 10))) 100
Add displayandnewlineexpressions at the beginning ofpair-tree-sum, as we did forlist- sum, and try it out again. Be sure you understand the output in terms of the recursive call pattern.
3.2.2 Using Equality Predicates
Suppose that Scheme didn't provide the predicate equal? to do structural comparisons. We
could write our own, because we have other type and equality predicates.
Let's write a simplied version of equal that works for lists, including nested lists. We'll consider objects to beour-equal? if they are either
if they're both pairs whose cars are our-equal?and whose cdrs are alsoour-equal?.
That is, we'll test lists recursively for structural equivalence, \bottoming out" when we hit something that's not a pair. This is pretty much what the standard Scheme predicateequal?does,
except that it can handle structured data types besides pairs. (For example, it considers two strings with the same character sequence equal?, even if they're two dierent objects.)
Scheme>(define (our-equal? a b) (cond ((eqv? a b)
#t)
((and (pair? a) (pair? b)
(our-equal? (car a) (car b)) (our-equal? (cdr a) (cdr b))) #t)
(else #f)))
This procedure checks the easy case rst (which is usually a good idea): if two objects areeqv?,
they're also our-equal?.
Otherwise, they're only our-equal?if they're both pairs and their cars are equal and their cdrs
are equal. Notice the use ofandhere. We rst check to see that they're pairs, and then take their
cars and cdrs and compare those. If they're not pairs, we won't ever take their cars and cdrs. (If we did, it would be an error, but we rely on the fact that andtests things sequentially and stops
when one test fails.) Try it out:
Scheme>(our-equal? '() '()) #t Scheme>(our-equal? 1 1) #t Scheme>(our-equal? 1 2) #f Scheme>(our-equal? '(1) '(1)) #t Scheme>(our-equal? '(1) '()) #f Scheme>(our-equal? '(1 (2)) '(1 (2))) #t Scheme>(our-equal? '(((3) 2) 1) '(((3) 2) (1))) #f Scheme>(our-equal? '((#f . #t) . (#f . #t)) '((#f . #t) . (#f . #t))) #t ================================================================== This is the end of Hunk H
At this point, you should go back to the previous chapter and read Hunk I before returning here and continuing this tutorial. ==================================================================
(Go BACK to read Hunk I, which starts at Section 2.4.3 Choosing Equality Predicates], page 47.