On this page:
1 Recursive unions
2 Data definition abstraction
3 Function abstraction
4 Built-in abstractions
5 Challenges

Lab 12: Review for the final exam

You may submit this lab to lab12 on Handin (this is optional).

Note: Whenever you write a function in this class, follow the design recipe. You will be graded accordingly. Note that choosing a built-in abstraction takes the place of the template step (Step 4).

1 Recursive unions

Exercise 1. A tree of Booleans is either a leaf containing a Boolean or a node containing two trees of Booleans (a left subtree and a right subtree). Write a data definition for TreeOfBooleans and the corresponding structure definitions. Call a leaf leaf and its unique field data, and call a node node and its two fields left and right.

Exercise 2. Write the template for processing a TreeOfBooleans.

Exercise 3. By “flipping a Boolean”, we mean replacing true with false and false with true. Write a function flip which takes a TreeOfBooleans and flips the data stored in its leaves.

Exercise 4. Write a function contains-true? which takes a TreeOfBooleans and returns true if and only if it contains a leaf storing true.

2 Data definition abstraction

Exercise 5. A tree of Strings is either a leaf containing a String or a node containing two trees of Strings (a left subtree and a right subtree). Write a data definition for trees of Strings using the structure definitions leaf and node.

Exercise 6. Write a data definition for a [TreeOf X] by abstracting over trees of Strings and trees of Booleans.

Exercise 7. Write the template for processing a [TreeOf X].

Exercise 8. Design a function tree-height which takes a [TreeOf X] and returns its height. A leaf has height 0. The height of a node is one plus the height of its taller subtree. You may find max useful.

3 Function abstraction

Exercise 9. Design a function sum-of-evens which takes a list of numbers and returns the sum of the even numbers in the input list. Use the template for processing a list.

Exercise 10. Add the following code to your definitions window:

(require 2htdp/image)
 
(define width 300)
(define height 400)
(define background (empty-scene width height))

Design a function draw-posns which takes a list of Posns and draws only those Posns which are within the boundaries of background. Use the template for processing a list.

Exercise 11. Abstract over sum-of-evens and draw-posns. Call your abstraction combine-some. Redefine sum-of-evens and draw-posns using combine-some.

Exercise 12. Design a function count-non-empty which takes a list of strings and returns how many non-empty strings it contains. Use combine-some.

4 Built-in abstractions

Download this recent version of the invaders code.

Exercise 13. The draw-invaders function is designed using the template for processing a list. Redefine draw-invaders using a built-in abstraction instead.

Exercise 14. The remove-invaders function is designed using the template for processing a list. Redefine remove-invaders using a built-in abstraction instead.

Exercise 15. The move-invaders function is designed using the template for processing a list. Redefine move-invaders using a built-in abstraction instead.

Exercise 16. The gen-invaders function is designed using the template for processing a natural number. Redefine gen-invaders using a built-in abstraction instead.

Exercise 17. The invaders-landed? function is designed using the template for processing a list. Redefine invaders-landed? using a built-in abstraction instead.

5 Challenges

Note: The following exercises are purely optional and more challenging than any problem on the final exam.

We’ve observed in class that foldr just “fills out the list-processing template”. We’ve also observed that the built-in list-processing abstractions can be defined using the template. In the next exercises, we’ll combine these two observations to see that foldr is the most abstract of the list-processing abstractions we have learned.

Exercise 18. Here is a renamed version of map:

; map-op : [X -> Y] [ListOf X] -> [ListOf Y]
; applies op to each element in lox
(define (map-op op lox)
  (map op lox))
 
(check-expect (map-op string-length empty) empty)
(check-expect (map-op string-length (list "tomato" "avocado" "zucchini"))
              (list 6 7 8))

Redefine map-op using foldr (instead of map). Hint: Use local.

Exercise 19. Here is a renamed version of filter:

; string-non-empty? : String -> Boolean
; checks if s is non-empty
(define (string-non-empty? s)
  (positive? (string-length s)))
 
(check-expect (string-non-empty? "cashews") true)
(check-expect (string-non-empty? "") false)
 
; filter-pred : [X -> Boolean] [ListOf X] -> [ListOf X]
; keeps elements of lox which satisfy pred
(define (filter-pred pred lox)
  (filter pred lox))
 
(check-expect (filter-pred string-non-empty? empty) empty)
(check-expect (filter-pred string-non-empty?
                (list "cashews" "" "peanuts" "almonds" ""))
              (list "cashews" "peanuts" "almonds"))

Redefine filter-pred using foldr (instead of filter). Hint: Use local.

Exercise 20. Here is a renamed version of ormap:

; fold-or : [X -> Boolean] [ListOf X] -> Boolean
; returns true if and only if at least one element of lox satisfies pred
(define (fold-or pred lox)
  (ormap pred lox))
 
(check-expect (fold-or zero? empty) false)
(check-expect (fold-or zero? (list 13 2 3 0 5 0)) true)
(check-expect (fold-or zero? (list 2 3 5 7)) false)

Redefine fold-or using foldr (instead of ormap). Hint: Use local.

Exercise 21. Here is a renamed version of andmap:

; fold-and : [X -> Boolean] [ListOf X] -> Boolean
; returns true if and only if all elements of lox satisfy pred
(define (fold-and pred lox)
  (andmap pred lox))
 
(check-expect (fold-and positive? empty) true)
(check-expect (fold-and positive? (list 13 2 3 0 5 0)) false)
(check-expect (fold-and positive? (list 2 3 5 7)) true)

Redefine fold-and using foldr (instead of andmap). Hint: Use local.