Comp 210 Lab 7: Abstract functions

Index: Some common abstract functions, Sorting

Some common abstract functions


In class you have seen filter:

     (define (filter keep? l)
           [(empty? l) empty]
           [(cons? l)  (cond
                           [(keep? (first l))
                            (cons (first l) (filter keep? (rest l)))]
                            (filter keep? (rest l))])]))


We are familiar with writing functions such as

and many others of similar form.

Since these functions are so similar, we'd like to package together the similar parts and separate out the different parts. We'll "package" the similar parts as a new function that can take either of the "different" parts as an argument that tells us what to do:

     ; map : ?? (see question below)
     (define (map f l)
           [(empty? l) empty]
           [(cons? l)  (cons (f (first l)) (map f (rest l)))]))

     (define (double-num n) (* 2 n))
     (define (double-nums a-lon) (map double-num a-lon))

     (define (lessthan3-num n) (< n 3))
     (define (lessthan3-nums a-lon) (map lessthan3-num a-lon))

We can write the following equation to understand map:

     (map f (list x1 ... xN)) = (list (f x1) ... (f xN))

map abstracts the general idea of "computing a new element from each old element and building a list of the new elements" away from what specifically you are computing from each element.

Q: What is the contract for map?

To do: Write double-nums using map and lambda, but without double-num.


We have written many functions to combine elements of a list, e.g., to sum the numbers in a list and to find the maximum element in a list. There are two versions of folding that prove to be very useful. Equationally, we can write

     (foldr f base (list x1 x2 ... xN)) = (f x1 (f x2 ... (f xN base)))
     (foldl f base (list x1 x2 ... xN)) = (f xN ... (f x2 (f x1 base))...)
Note how the two versions combine the elements of the input list in opposite order. Both are built-in to Scheme.

Q: Based upon these equations, what should the following produce?

     (foldr cons empty (list -1 5 -3 4 2))
     (foldl cons empty (list -1 5 -3 4 2))

To do: Define the function foldr to satisfy the above equation. It follows the template for a function consuming a list.

To do: Using foldr, define functions to compute


For the curious...


The following two functions implement one algorithm for sorting a list of numbers.

     ; insert<-num : number list-of-number (number number -> boolean) -> list-of-number
     ;    assumes the input list is sorted non-descending
     ;    returns a new sorted non-descending list with the input number in it
     (define (insert<-num n a-lon)
        (cond [(empty? a-lon)
               (cons n empty)]
              [(cons? a-lon)
               (cond [(< n (first a-lon))
                      (cons n a-lon)]
                      (cons (first a-lon) (insert<-num n (rest a-lon)))])]))

     ; isort<-nums : list-of-number -> list-of-number
     ;   returns a new sorted non-descending version of the input list
     (define (isort<-nums a-lon)
        (cond [(empty? a-lon) empty]
              [(cons? a-lon)  (insert<-num (first a-lon)
                                              (isort<-nums (rest a-lon))))))
For example
     (insert<-num 3 empty)        = (list 3)
     (insert<-num 1 (list 3 4 7)) = (list 1 3 4 7)
     (insert<-num 3 (list 1 4 7)) = (list 1 3 4 7)
     (insert<-num 7 (list 1 3 4)) = (list 1 3 4 7)

     (isort<-nums empty)          = empty
     (isort<-nums (list 7 1 4 3)) = (list 1 3 4 7)

The above code only sorts numbers in non-descending order (because of the test <). To do:

  1. Abstract the code so that we can specify the ordering operator and sort any kind of data in any kind of order. Don't forget to abstract the contracts also.
  2. Modify the code to use our standard abstract functions where possible.
  3. Use your abstracted version for the original numerical non-descending sort and other sorts.
A solution.