Lab 6 - Abstraction and natural number recursion
Purpose In this lab we will practice recognizing similarities in function definitions and in data definitions and how to avoid them. This lab also has some fun with natural number recursion.
- Work in pairs
- Change roles often!
- Follow the design recipe for every problem.
Abstraction
Sometimes when we solve problems, we find that the solution to one problem
looks a lot like the solution to another one. Check out the following functions
and data definition. From now on we will leave out the definition for lists,
and use the [List-of X]
notation.
;; A [List-of Number] is one of ;; -- empty ;; -- (cons Number [List-of Number]) ;; lon-add2 : [List-of Number] -> [List-of Number] ;; Add two (2) to each element of the given list of numbers (define (lon-add2 lon) (cond [(empty? lon) empty] [else (cons (+ (first lon) 2) (lon-add2 (rest lon)))])) ;; lon-add5 : [List-of Number] -> [List-of Number] ;; Add five (5) to each element of the given list of numbers (define (lon-add5 lon) (cond [(empty? lon) empty] [else (cons (+ (first lon) 5) (lon-add5 (rest lon)))]))
Is it clear what each function does? You are hopefully asking "Why would you do that?!" since they are almost exactly the same.
-
Write a function named
lon-add-n
that abstracts both of the functions above, taking an extra argument, which is the number to be added to each element. -
Rewrite both
lon-add2
andlon-add5
using your more general function, and write a few tests for each to be sure they work as expected.
;; A [List-of String] is one of ;; -- empty ;; -- (cons String [List-of String])
-
Write a function named
starts-with-cat
that consumes a [List-of String] and constructs a list of those strings that start with "cat". -
Write a function named
starts-with-dog
that consumes a [List-of String] and constructs a list of those strings that start with "dog". -
Write a function named
starts-with
that abstracts both of the functions above, taking an extra argument, which is the substring to be found in each element. -
Rewrite both
starts-with-cat
andstarts-with-dog
using your more general function, and write a few tests for each to be sure they work as expected.
Recursion over natural numbers
A recursive data structure we use very often in programming is the collection of natural numbers:
;; A Nat (natural number) is one of: ;; - 0 ;; - (add1 Nat) ;; ;; 0 predicate: zero? ;; ;; (add1 n) predicate: positive? ;; (add1 n) accessor: sub1
-
What is the template for
Nat
?
In the following exercises we will redefine some built-in arithmetic
functions to get practice writing recursive functions over Nat
s, so don't simply reuse the built-in functions.
-
Design a function
nat-even?
that returnstrue
if the givenNat
is even.You may only use
sub1
(and possiblynot
). E.g., do not useeven?
,odd?
,modulo
, etc. -
Design a function
double
that doubles the givenNat
. Again, you may only useadd1
andsub1
(anddouble
of course). -
Design a function
down-from
that takes aNat
n
and returns the list ofNat
s counting down fromn
. For example,(down-from 3) = (list 3 2 1 0)
. -
Design a function
repeat
that takes aNat
n
and aString
s
and returns a list that repeatss
n
times. For example,(repeat "buffalo" 8) = (list "buffalo" "buffalo" "buffalo" "buffalo" "buffalo" "buffalo" "buffalo" "buffalo")
. Do not usemake-list
! (though it's good to know about) -
Design a function
nat+
that takes twoNat
s and computes their sum. (Use recursion, not the built-in+
function.) -
Design a function
nat*
that takes twoNat
s and computes their product. (Again use recursion, not the built-in*
function, though you may use yournat+
now.) -
Challenge: Design a function
sqware
that squares the givenNat
(Note the intended name misspelling!), WITHOUT usingnat*
! You may useadd1
,sub1
,double
, andnat+
(andsqware
of course).
Concentric rings in the World
Some basic setup:
(require 2htdp/image) (require 2htdp/universe) (define width 400) (define height 400)In this animation, a
World
is a collection of Ring
s, each of which has a
size and a location.
; A World is a [listof Ring] ; A Ring is a (make-ring Nat Posn) (define-struct ring (size center))
-
Design a
grow-ring
function that increases aRing
's size by 1. -
Design a little
draw-ring
function that takes aNat
r
as input and simply returns an image of a circle with radiusr
. (We'll make this more interesting later.) -
Design a
place-ring
function that draws aRing
into the givenScene
at theRing
's location. (Usedraw-ring
here so that we can modify it later to change the animation.) -
Design a
draw
function that renders aWorld
as aScene
by drawing all theRing
s in their correct locations. -
Design a
mouse
function that, when the mouse is clicked, adds a 0-sizeRing
to theWorld
at the location of the click. -
Design a
tick
function that grows all theRing
s in theWorld
usinggrow-ring
. -
Now let's redesign the
draw-ring : Nat -> Image
function. Instead of making an image of a solid circle, let's make concentric rings of many circles. We can achieve this by overlaying many circles of increasing sizes:(overlay
) =
Put it all together and see what you get:
(big-bang empty (on-tick tick .25) (to-draw draw) (on-mouse mouse))