Index: Some common abstract functions, Sorting

In class you have seen `filter`:

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

We are familiar with writing functions such as

- "given a list of numbers
*x*, return a list of numbers*2*x*":; double-nums : list-of-number -> list-of-number (define (double-nums a-lon) (cond [(empty? a-lon) empty] [(cons? a-lon) (cons (* 2 (first a-lon)) (double-nums (rest a-lon)))]))

- "given a list of numbers
*x*, return a list of booleans*x < 3*"; lessthan3-nums : list-of-number -> list-of-boolean (define (lessthan3-nums a-lon) (cond [(empty? a-lon) empty] [(cons? a-lon) (cons (< (first a-lon) 3) (lessthan3-nums (rest a-lon)))]))

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) (cond [(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

- the sum of a list of numbers,
- maximum of a list of numbers,
- whether all elements in a list of booleans are true, and
- whether all elements in a list of numbers are greater than 6.

**Q:**

- What is the contract for
`foldr`(and`foldl`), assuming the input list is a list of numbers? - What is the contract for
`foldr`(and`foldl`) in general?

**For the curious...**

- Defining
`foldl`would be difficult for you at this point in the course. -
**To do:**`map`and`foldr`each abstract part of the standard template for lists.`map`abstracts the computation on each element of the input list, while`foldr`abstracts the combining on the first element and the recursive call on the other elements. Write a function`map-and-foldr`which abstracts all the pieces. -
**To do:**Write`filter`using`foldr`. -
**To do:**Write`map`using`foldr`.

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)] [else (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:**

- 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.
- Modify the code to use our standard abstract functions where possible.
- Use your abstracted version for the original numerical non-descending sort and other sorts.