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
; 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)))]))
; 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
Q:
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)]
[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: