;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-intermediate-reader.ss" "lang")((modname 11-abstraction) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) ;; Abstraction! (require 2htdp/image) (require 2htdp/universe) ;; What do these have in common? ; An LoN is one of: ; - '() ; - (cons Number LoN) ; contains-4? : LoN -> Boolean ; Does the given list contain 4? ; ; Strategy: struct. decomp. (define (contains-4? lon) (cond [(empty? lon) false] [else (if (= (first lon) 4) true (contains-4? (rest lon)))])) (check-expect (contains-4? empty) false) (check-expect (contains-4? (list 1 4 30)) true) (check-expect (contains-4? (list 1 0 30)) false) ; contains-7? : LoN -> Boolean ; Does the given list contain 7? ; ; Strategy: struct. decomp. (define (contains-7? lon) (cond [(empty? lon) false] [else (if (= (first lon) 7) true (contains-7? (rest lon)))])) (check-expect (contains-7? empty) false) (check-expect (contains-7? (list 1 7 30)) true) (check-expect (contains-7? (list 1 0 30)) false) ; contains-17? : LoN -> Boolean ; Does the given list contain 17? ; ; Strategy: struct. decomp. (define (contains-17? lon) (cond [(empty? lon) false] [else (if (= (first lon) 17) true (contains-17? (rest lon)))])) (check-expect (contains-17? empty) false) (check-expect (contains-17? (list 1 17 30)) true) (check-expect (contains-17? (list 1 0 30)) false) ;; RECIPE FOR ABSTRACTION ;; ;; 1. Are the functions similar? If not, don't do it. If so, ;; mark differences with difference lines. ;; ;; 2. Make a copy of one function, but with a new name. Add a parameter ;; for each difference line, add them to the recursive calls, and replace ;; the difference line expressions. ;; ;; 3. Redefine original functions using the abstraction. ;; ;; 4. Redo the original tests using the abstraction. ;; ;; 5. Develop a generalized signature for the abstraction. ;; ;; 6. If possible, state the purpose using "...". ; contains-n? : Number LoN -> Boolean ; Does the given list contain n? ; (contains-n? n (list a-1 ... a-k)) = (or (= n a-1) ... (= n a-k)) ; ; Strategy: struct. decomp. (define (contains-n? n lon) (cond [(empty? lon) false] [else (if (= (first lon) n) true (contains-n? n (rest lon)))])) (check-expect (contains-n? 4 empty) false) (check-expect (contains-n? 4 (list 1 4 30)) true) (check-expect (contains-n? 4 (list 1 0 30)) false) ; contains-4?*, contains-7?*, contains-17?* : LoN -> Boolean ; Does the given list contain {4, 7, 17}? ; ; Strategy: function composition (define (contains-4?* lon) (contains-n? 4 lon)) (define (contains-7?* lon) (contains-n? 7 lon)) (define (contains-17?* lon) (contains-n? 17 lon)) (check-expect (contains-4?* empty) false) (check-expect (contains-4?* (list 1 4 30)) true) (check-expect (contains-4?* (list 1 0 30)) false) (check-expect (contains-7?* empty) false) (check-expect (contains-7?* (list 1 7 30)) true) (check-expect (contains-7?* (list 1 0 30)) false) (check-expect (contains-17?* empty) false) (check-expect (contains-17?* (list 1 17 30)) true) (check-expect (contains-17?* (list 1 0 30)) false) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; An LoN is one of: ; - '() ; - (cons Number LoN) ; lon-length : LoN -> Natural ; Finds the length of a list of numbers. ; ; Strategy: struct. decomp. (define (lon-length lon) (cond [(empty? lon) 0] [else (add1 (lon-length (rest lon)))])) (check-expect (lon-length empty) 0) (check-expect (lon-length (list 1 2 3)) 3) ; An LoS is one of: ; - '() ; - (cons String LoS) ; los-length : LoS -> Natural ; Finds the length of a list of strings. ; ; Strategy: struct. decomp. (define (los-length los) (cond [(empty? los) 0] [else (add1 (los-length (rest los)))])) (check-expect (los-length empty) 0) (check-expect (los-length (list "one" "two" "three")) 3) ; An LoI is one of: ; - '() ; - (cons Image LoI) ; loi-length : LoI -> Natural ; Finds the length of a list of images. ; ; Strategy: struct. decomp. (define (loi-length loi) (cond [(empty? loi) 0] [else (add1 (loi-length (rest loi)))])) (check-expect (loi-length empty) 0) (check-expect (loi-length (list (text "1" 12 "red") (text "2" 12 "red") (text "3" 12 "red"))) 3) ; For any X, a [Listof X] is one of: ; - '() ; - (cons X [Listof X]) ; lox-length : [Listof X] -> Natural ; Finds the length of a list. ; ; Strategy: struct. decomp. (define (lox-length lox) (cond [(empty? lox) 0] [else (add1 (lox-length (rest lox)))])) (check-expect (lox-length empty) 0) (check-expect (lox-length (list 1 2 3)) 3) (check-expect (lox-length (list "one" "two" "three")) 3) (check-expect (lox-length (list (text "1" 12 "red") (text "2" 12 "red") (text "3" 12 "red"))) 3) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; filter<3 : [Listof Number] -> [Listof Number] ; Keeps the numbers less than 3. ; ; Strategy: struct. decomp. (define (filter<3 lon) (cond [(empty? lon) empty] [else (if (< (first lon) 3) (cons (first lon) (filter<3 (rest lon))) (filter<3 (rest lon)))])) (check-expect (filter<3 empty) empty) (check-expect (filter<3 (list 1 3 5 2 4 6)) (list 1 2)) ; filter<6 : [Listof Number] -> [Listof Number] ; Keeps the numbers less than 6. ; ; Strategy: struct. decomp. (define (filter<6 lon) (cond [(empty? lon) empty] [else (if (< (first lon) 6) (cons (first lon) (filter<6 (rest lon))) (filter<6 (rest lon)))])) (check-expect (filter<6 empty) empty) (check-expect (filter<6 (list 1 3 5 2 4 6)) (list 1 3 5 2 4)) ;; Abstraction motto: "Copy and paste makes waste." ; filter [Listof Number] ; Keeps the numbers less than n. ; ; Strategy: struct. decomp. (define (filter=n : Number [Listof Number] -> [Listof Number] ; Keeps the numbers greater than or equal to n. ; ; Strategy: struct. decomp. (define (filter>=n n lon) (cond [(empty? lon) empty] [else (if (>= (first lon) n) (cons (first lon) (filter>=n n (rest lon))) (filter>=n n (rest lon)))])) (check-expect (filter>=n 3 empty) empty) (check-expect (filter>=n 6 empty) empty) (check-expect (filter>=n 3 (list 1 3 5 2 4 6)) (list 3 5 4 6)) (check-expect (filter>=n 6 (list 1 3 5 2 4 6)) (list 6)) ; filter-compare-n : [Number Number -> Number] Number [Listof Number] -> ; [Listof Number] ; Keeps all the numbers for which the comparison to n returns true. ; ; Strategy: struct. decomp. (define (filter-compare-n compare n lon) (cond [(empty? lon) empty] [else (if (compare (first lon) n) (cons (first lon) (filter-compare-n compare n (rest lon))) (filter-compare-n compare n (rest lon)))])) (check-expect (filter-compare-n < 3 empty) empty) (check-expect (filter-compare-n < 6 empty) empty) (check-expect (filter-compare-n < 3 (list 1 3 5 2 4 6)) (list 1 2)) (check-expect (filter-compare-n < 6 (list 1 3 5 2 4 6)) (list 1 3 5 2 4)) (check-expect (filter-compare-n >= 3 empty) empty) (check-expect (filter-compare-n >= 6 empty) empty) (check-expect (filter-compare-n >= 3 (list 1 3 5 2 4 6)) (list 3 5 4 6)) (check-expect (filter-compare-n >= 6 (list 1 3 5 2 4 6)) (list 6)) ; filter-longer-than-4 : [Listof String] -> [Listof String] ; Keeps all the strings of length greater than 4. ; ; Strategy: struct. decomp. (define (filter-longer-than-4 los) (cond [(empty? los) empty] [else (if (> (string-length (first los)) 4) (cons (first los) (filter-longer-than-4 (rest los))) (filter-longer-than-4 (rest los)))])) (check-expect (filter-longer-than-4 empty) empty) (check-expect (filter-longer-than-4 (list "filter" "longer" "than" "4")) (list "filter" "longer")) ; filter-pred : [X -> Boolean] [Listof X] -> [Listof X] ; Keeps all the elements satisfying the given predicate. ; ; Strategy: struct. decomp. (define (filter-pred pred? lox) (cond [(empty? lox) empty] [else (if (pred? (first lox)) (cons (first lox) (filter-pred pred? (rest lox))) (filter-pred pred? (rest lox)))])) ; filter-compare-n* : [Number Number -> Number] Number [Listof Number] -> ; [Listof Number] ; To keep all the numbers for which the comparison to n returns true. ; ; Strategy: function composition (define (filter-compare-n* compare n lon) (local [(define (compare-n? m) (compare m n))] (filter-pred compare-n? lon))) ; filter-longer-than-4* : [Listof String] -> [Listof String] ; To keep all the strings of length greater than 4. ; ; Strategy: function composition (define (filter-longer-than-4* los) (local [(define (longer-than-4? s) (> (string-length s) 4))] (filter-pred longer-than-4? los))) (check-expect (filter-compare-n* < 3 empty) empty) (check-expect (filter-compare-n* < 6 empty) empty) (check-expect (filter-compare-n* < 3 (list 1 3 5 2 4 6)) (list 1 2)) (check-expect (filter-compare-n* < 6 (list 1 3 5 2 4 6)) (list 1 3 5 2 4)) (check-expect (filter-compare-n* >= 3 empty) empty) (check-expect (filter-compare-n* >= 6 empty) empty) (check-expect (filter-compare-n* >= 3 (list 1 3 5 2 4 6)) (list 3 5 4 6)) (check-expect (filter-compare-n* >= 6 (list 1 3 5 2 4 6)) (list 6)) (check-expect (filter-longer-than-4* empty) empty) (check-expect (filter-longer-than-4* (list "filter" "longer" "than" "4")) (list "filter" "longer")) ; compare-to : [X X -> Boolean] X -> [X -> Boolean] ; To create a predicate to compare to a given value. ; ; Strategy: function composition (define (compare-to compare x) (local [(define (pred? y) (compare y x))] pred?)) (check-expect (filter-pred (compare-to < 3) empty) empty) (check-expect (filter-pred (compare-to < 6) empty) empty) (check-expect (filter-pred (compare-to < 3) (list 1 3 5 2 4 6)) (list 1 2)) (check-expect (filter-pred (compare-to < 6) (list 1 3 5 2 4 6)) (list 1 3 5 2 4)) (check-expect (filter-pred (compare-to >= 3) empty) empty) (check-expect (filter-pred (compare-to >= 6) empty) empty) (check-expect (filter-pred (compare-to >= 3) (list 1 3 5 2 4 6)) (list 3 5 4 6)) (check-expect (filter-pred (compare-to >= 6) (list 1 3 5 2 4 6)) (list 6)) ;; You don't need to write filter-pred, because filter is built in. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Other things that should annoy us: ; add2-to-list : [Listof Number] -> [Listof Number] ; Adds 2 to every element of a list. ; ; Strategy: struct. decomp. (define (add2-to-list lon) (cond [(empty? lon) empty] [else (cons (+ 2 (first lon)) (add2-to-list (rest lon)))])) (check-expect (add2-to-list (list 0 2 3 7)) (list 2 4 5 9)) ; lon->los : [Listof Number] -> [Listof String] ; Converts every number in the list to a string ; ; Strategy: struct. decomp. (define (lon->los lon) (cond [(empty? lon) empty] [else (cons (number->string (first lon)) (lon->los (rest lon)))])) (check-expect (lon->los (list 0 2 3 7)) (list "0" "2" "3" "7")) ; make-red-circles : [Listof Number] -> [Listof Image] ; Maps each number to a solid, red circle of that radius. ; ; Strategy: struct. decomp. (define (make-red-circles lon) (cond [(empty? lon) empty] [else (cons (circle (first lon) "solid" "red") (make-red-circles (rest lon)))])) (check-expect (make-red-circles (list 1 2 3 7)) (list (circle 1 "solid" "red") (circle 2 "solid" "red") (circle 3 "solid" "red") (circle 7 "solid" "red"))) ; A Ball is (make-ball Posn Vel) ; A Vel is (make-vel Number Number) (define-struct ball (posn vel)) (define-struct vel (dx dy)) ; move-ball : Ball -> Ball ; Updates the position of a ball by its velocity. ; ; Strategy: struct. decomp. (define (move-ball a-ball) (make-ball (add-velocity (ball-vel a-ball) (ball-posn a-ball)) (ball-vel a-ball))) (check-expect (move-ball (make-ball (make-posn 3 5) (make-vel -1 -7))) (make-ball (make-posn 2 -2) (make-vel -1 -7))) ; add-velocity : Vel Posn -> Posn ; Updates each posn component by the corresponding velocity component. ; ; Strategy: struct. decomp. (define (add-velocity v p) (make-posn (+ (posn-x p) (vel-dx v)) (+ (posn-y p) (vel-dy v)))) (check-expect (add-velocity (make-vel -1 -7) (make-posn 3 5)) (make-posn 2 -2)) ; move-balls : [Listof Ball] -> [Listof Ball] ; Updates the position of each ball by its velocity. ; ; Strategy: struct. decomp. (define (move-balls lob) (cond [(empty? lob) empty] [else (cons (move-ball (first lob)) (move-balls (rest lob)))])) (check-expect (move-balls empty) empty) (check-expect (move-balls (list (make-ball (make-posn 3 5) (make-vel -1 -7)) (make-ball (make-posn 3 5) (make-vel 0 0)) (make-ball (make-posn 3 5) (make-vel 2 0)))) (list (make-ball (make-posn 2 -2) (make-vel -1 -7)) (make-ball (make-posn 3 5) (make-vel 0 0)) (make-ball (make-posn 5 5) (make-vel 2 0)))) ; my-map : [X -> Y] [Listof X] -> [Listof Y] ; (my-map f (list x-1 ... x-k)) = (list (f x-1) ... (f x-k)) ; ; Strategy: struct. decomp. (define (my-map f lox) (cond [(empty? lox) empty] [else (cons (f (first lox)) (my-map f (rest lox)))])) ; add2 : Number -> Number ; To add 2. ; ; Strategy: function composition (define (add2 n) (+ 2 n)) (check-expect (my-map add2 (list 0 2 3 7)) (list 2 4 5 9)) (check-expect (my-map number->string (list 0 2 3 7)) (list "0" "2" "3" "7")) (check-expect (local [(define (make-red-circle r) (circle r "solid" "red"))] (my-map make-red-circle (list 1 2 3 7))) (list (circle 1 "solid" "red") (circle 2 "solid" "red") (circle 3 "solid" "red") (circle 7 "solid" "red"))) (check-expect (my-map move-ball empty) empty) (check-expect (my-map move-ball (list (make-ball (make-posn 3 5) (make-vel -1 -7)) (make-ball (make-posn 3 5) (make-vel 0 0)) (make-ball (make-posn 3 5) (make-vel 2 0)))) (list (make-ball (make-posn 2 -2) (make-vel -1 -7)) (make-ball (make-posn 3 5) (make-vel 0 0)) (make-ball (make-posn 5 5) (make-vel 2 0)))) ;; You don't need to write my-map, since map is built in. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; sum : [Listof Number] -> Number ; Sums the numbers in a list. ; ; Strategy: struct. decomp. (define (sum lon) (cond [(empty? lon) 0] [else (+ (first lon) (sum (rest lon)))])) (check-expect (sum (list 3 4 5)) 12) ; product : [Listof Number] -> Number ; Multiplies the numbers in a list. ; ; Strategy: struct. decomp. (define (product lon) (cond [(empty? lon) 1] [else (* (first lon) (product (rest lon)))])) (check-expect (product (list 3 4 5)) 60) ; concat : [Listof String] -> String ; Appends the strings in a list. ; ; Strategy: struct. decomp. (define (concat los) (cond [(empty? los) ""] [else (string-append (first los) (concat (rest los)))])) (check-expect (concat (list "Hello" ", w" "orld")) "Hello, world") ; fold-right : [X Y -> Y] Y [Listof X] -> Y ; (fold-right f b (list x-1 x-2 ... x-k)) ; = (f x-1 (f x-2 ... (f x-k b) ...)) ; Combines the elements of a list using some operation. ; ; Strategy: struct. decomp. (define (fold-right combine start lox) (cond [(empty? lox) start] [else (combine (first lox) (fold-right combine start (rest lox)))])) (check-expect (fold-right + 0 (list 3 4 5)) 12) (check-expect (fold-right * 1 (list 3 4 5)) 60) (check-expect (fold-right string-append "" (list "Hello" ", w" "orld")) "Hello, world") ; superimpose : Scene [Listof Image] -> Scene ; Superimposes the images in a list onto a given scene. ; ; Strategy: function composition (define (superimpose scene loi) (local [(define (place-at-origin image scene) (place-image image 0 0 scene))] (fold-right place-at-origin scene loi))) (check-expect (superimpose (empty-scene 400 400) (list (circle 200 "outline" "red") (circle 300 "outline" "green"))) (place-image (circle 200 "outline" "red") 0 0 (place-image (circle 300 "outline" "green") 0 0 (empty-scene 400 400)))) ;; fold-right is called foldr ;; Every function recursive on one list that you've written in this ;; class thus far can be written using foldr.