We're going to design some nice abstract functions, and have
some more fun with Posn
s, but before we do let's
make sure we can use more abstract data definitions.
We start with aList
warmup. Here's are usual data definitions forList
s:;; A LoN is one of ;; - empty ;; - (cons Number LoN) ;; A LoS is one of ;; - empty ;; - (cons Symbol LoS)
- What are the contracts of
cons
,append
, andlength
forLoS
andLoN
definitions? Hint: the contracts oflist
would be something like this:;; list : Number ... Number -> LoN ;; list : Symbol ... Symbol -> LoS
- Abstract these two data definitions into a single definition for
[Listof X]
.
- What would the more general contracts of
cons
,append
, andlength
be now? Hint: the general contract oflist
would be something like this:;; list : X ... X -> [Listof X]
Part 2: Abstracting Functions
First, we abstract plain values within function definitons.
- Design a function that consumes a
[Listof Number]
and checks if 0 is in the list.
- Design a function that consumes a
[Listof Number]
and checks if 5 is in the list.
- Abstract the previous two functions and design a function that consumes an
[Listof Number]
and aNumber
and checks if the number is in the list.** Make sure your new function has a precise contract...
- Comment out the bodies of your previous functions and rewrite them using your abstraction. Much shorter (and useful) right?
As we saw in lecture, functions are just a special type of value. We'll say that again: functions are just a special type of value!
Now we abstract over values again, but this time they will be functions.
- Design a function that consumes a
[Listof Any]
and removes all theSymbol
s from the list. How do you know when something is aSymbol
?
- Design a function that consumes a
[Listof Any]
and removes all theNumber
s from the list.
- Abstract these two into a single function, called
filter-out
, that takes a predicate function to determine which elements to remove from the list.Hint: The contract of your abstract function should look something like this:
;; filter-out : [Listof Any] [Any -> Boolean] -> [Listof Any]
Though you could also change the order of the parameters.
Part 3: DrRacket's "loop" functions
DrRacket has built-in functions to help us write functions that deal with lists. (See the HTDP link here.)
For the functions below, remember that DrRacket has the functions
odd?
andeven?
built-in, both are[Number -> Boolean]
- Design a function
all-odd?
that takes a[Listof Number]
and returnstrue
if all the numbers in the list are odd, andfalse
otherwise. Hint: useandmap
- Design the same function, call it
all-odd-2?
, but useormap
this time. Hint: if all the numbers are odd, then none of them are even, right?
- Design the function
between
that takes two numbers (saylow
andhigh
) and returns a list of all numbers fromlow
tohigh-1
(inclusive). Usebuild-list
.
Hint: The first argument tobuild-list
is the length of the list that you want to build. The second argument is a function that takes an argument i and returns the item that you want to be at position i in the list (starting from 0!).
- Using your function
between
, design the functionevens
that takes two numbers, and returns a list of all the even numbers in that range. Usefilter
.
- Using
foldr
orfoldl
, implement the functionsum
that computes the sum of all the elements in a list of numbers.
Study this function definition:
;; minus-all : Number [listof Number] -> Number ;; Subtract all the numbers in the list from the given one (define (minus-all n lon) (foldl - n lon)) (check-expect (minus-all 20 empty) 20) (check-expect (minus-all 20 (list 5 2)) 13) (check-expect (minus-all 20 (list 5 4 3 2 1)) 5)
- Why doesn't this function work? Fix the function so that it produces the correct results. Hint: subtraction is not commutative... i.e., it is order dependent. Try using
local
orlambda
to modify the ordering thatfoldl
is doing the subtraction.
Part 4: Fun with
local
, and Loop functionsThe goal of this part of the Lab is to use the ISL loop functions (e.g.,
map
,foldr
...) to do cool stuff (for a Computer Science graduate student's definition of cool).Here are some definitions to get you going...
(require 2htdp/universe) (require 2htdp/image) ;; Scene Width and Height... (define WIDTH 400) (define HEIGHT 400) ;; A Planet is: ;; (make-planet Number Number Number Number String) (define-struct planet (x y vx vy color)) ;; x,y represent the planet's current location, and vx,vy represent ;; its velocity (speed/direction) ;; Number of colors (define NUM-COLORS 3) ;; color-for : Number -> String ;; Return a color for the given number (define (color-for n) (cond [(= n 0) "red"] [(= n 1) "green"] [else "blue"]))A
Planet
represents an object (presumably in space) that will act and react to other objects. Our World State will be a[Listof Planet]
.While we're here... add some more colors if you want.
- Design the function
move-all
that moves a[Listof Planet]
in the speed/direction each is headed. This means creating a newPlanet
with new-x = x + vx and new-y = y + vy. Don't change the velocities.Create a
local
function that moves a singlePlanet
, and usemap
.Now for the brain-bender... Here's some more code that does the math for you. See if you can understand what it's doing:
- Design the function
draw-lop
that draws a[Listof Planet]
in anempty-scene
.Create a
local
function that adds aPlanet
to aScene
, and usefoldr
.;; distance : Planet Planet -> Number ;; Calculate the distance between the Planets (define (distance p1 p2) (sqrt (+ (sqr (- (planet-x p1) (planet-x p2))) (sqr (- (planet-y p1) (planet-y p2)))))) ;; apply-gravity : Planet Planet -> Planet ;; Apply the gravitational effects of the other Planet to the ;; second Planet (note the order of the arguments...) (define (apply-gravity p-other p) (local [(define dist (distance p p-other)) (define dx (- (planet-x p) (planet-x p-other))) (define dy (- (planet-y p) (planet-y p-other)))] (cond [(< dist 1) p] [else (make-planet (planet-x p) (planet-y p) (- (planet-vx p) (/ dx dist)) (- (planet-vy p) (/ dy dist)) (planet-color p))])))
- Design the function
gravity-one
that usesapply-gravity
to apply the gravitational effects of the[Listof Planet]
to a singlePlanet
. Here's what your contract should be:;; gravity-one : Planet [Listof Planet] -> Planet
Use use
foldr
. Hint: No helper required!
- Design the function
gravity-all
that usesgravity-one
to apply the effects of allPlanet
s to all thePlanet
s. Your contract should be:;; gravity-all : [Listof Planet] -> [Listof Planet]
Create a
local
function that callsgravity-one
, then usemap
. Make sure your contract matches up with the general contract ofmap
. (just ask if you need help)
Yes! Now we're all set to roll. Here's the Big-Bang code to finish it all off.;; tick : [Listof Planet] -> [Listof Planet] ;; Apply gravity, then move all the Planets (define (tick lop) (move-all (gravity-all lop))) ;; mouse : [Listof Planet] Number Number String -> [Listof Planet] ;; Add a new planet where the mouse was clicked (define (mouse lop x y me) (cond [(string=? me "button-down") (cons (make-planet x y 0 0 (color-for (random NUM-COLORS))) lop)] [else lop])) ;; Start with no planets... (define last (big-bang empty (on-mouse mouse) (to-draw draw-lop) (on-tick tick 1/20)))Enjoy!