# Comp 210 Lab 7: Abstract functions

## Some common abstract functions

### filter

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))])]))
```

### map

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)))]))
```
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)
(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.

### fold

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.

## Sorting

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:

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.