We're going to design some nice abstract functions, and have
some more fun with Posns, but before we do let's
make sure we can use more abstract data definitions.
We start with aListwarmup. Here's are usual data definitions forLists:;; 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, andlengthforLoSandLoNdefinitions? Hint: the contracts oflistwould 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, andlengthbe now? Hint: the general contract oflistwould 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 aNumberand 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 theSymbols from the list. How do you know when something is aSymbol?
- Design a function that consumes a
[Listof Any]and removes all theNumbers 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 returnstrueif all the numbers in the list are odd, andfalseotherwise. Hint: useandmap
- Design the same function, call it
all-odd-2?, but useormapthis time. Hint: if all the numbers are odd, then none of them are even, right?
- Design the function
betweenthat takes two numbers (saylowandhigh) and returns a list of all numbers fromlowtohigh-1(inclusive). Usebuild-list.
Hint: The first argument tobuild-listis 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 functionevensthat takes two numbers, and returns a list of all the even numbers in that range. Usefilter.
- Using
foldrorfoldl, implement the functionsumthat 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
localorlambdato modify the ordering thatfoldlis 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
Planetrepresents 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-allthat moves a[Listof Planet]in the speed/direction each is headed. This means creating a newPlanetwith new-x = x + vx and new-y = y + vy. Don't change the velocities.Create a
localfunction 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-lopthat draws a[Listof Planet]in anempty-scene.Create a
localfunction that adds aPlanetto 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-onethat usesapply-gravityto apply the gravitational effects of the[Listof Planet]to a singlePlanet. Here's what your contract should be:;; gravity-one : Planet [Listof Planet] -> PlanetUse use
foldr. Hint: No helper required!
- Design the function
gravity-allthat usesgravity-oneto apply the effects of allPlanets to all thePlanets. Your contract should be:;; gravity-all : [Listof Planet] -> [Listof Planet]Create a
localfunction 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!