[ L01 L02 L03 L04 L05 L06 L07 L08 L09 L10 L11 L12 L13 L14 L15 L16 L17 L18 L19 L20 L21 L22 L23 ]
To prepare for this lecture First be sure that you are totally comfortable with HtdW. If you need any help with this ask on Piazza or go to office hours.
Then watch the "Reference Rule Part 1" and "Reference Rule Part 2" videos. This is a rare case where we mean just watch, not work through. But, do pay close attention; you will need to have watched it in order to be able to work through the example we will do next time. The clicker question will probably be from this unit!
In this lecture we will design a world program in which the world state is a list of elements, for which we will have a separate data definition.
By the end of the lecture—including the post-lecture work—you should be able to:
The starters for this lecture are:
NOTE: Starter files with numbers in their names show a progression of intermediate states of solving the problem.
Here is the solution for this lecture:
Once again, congratulate yourself on the hard work in lecture today. Ask yourself whether you could have understood much less written that program at the start of the term. So even if you struggled with lecture you should feel proud of how much you have learned. And you can use the lecture as a measure of getting ready for the midterm.
This lecture is the last one in module 4. To complete module 4 you should:
There are three key points in this lecture that you want to be sure you understand:
(1) The information we needed to represent consisted of an arbitrary number of non-atomic entities (i.e. eggs). To do that we end up with two types: one for the individual entities (eggs), and one for the arbitrary number of them (the list).
The type comments have self-reference and reference arrows, and the templates have corresponding natural recursion and natural helper arrows.
(2) The natural helper in the template means that if a function based on the template (next-eggs, render-eggs) needs to perform some operation on the referred to type, then it must call a single function, with that type in its signature, to perform that operation.
So next-eggs needs to call a new function next-egg to advance the egg, rather than calling all three of egg-x egg-y egg-r.
(3) One of the key issues is figuring out what arguments the natural helper will receive. Specifically does the natural helper receive the result of the natural recursion as an argument or not. In other words, is the helper in combination position or contribution position. Consider these two cases:
(check-expect (next-eggs (cons (make-egg 100 200 300) (cons (make-egg 400 500 600) empty))) (cons (make-egg 100 (+ 200 FALL-SPEED) (+ 300 SPIN-SPEED)) (cons (make-egg 400 (+ 500 FALL-SPEED) (+ 600 SPIN-SPEED)) empty)))
In this case we can see that cons is in the combination position. That's because it accepts the result of the natural recursion as an argument (2nd in this case). Make-egg is in the contribution position. The make-egg part of the example needs access to two or more of the fields, so the natural helper will take care of the make-egg functionality (contribution of the first) and cons is the combination.
(define (next-eggs loe) (cond [(empty? loe) empty] [else (cons (next-egg (first loe)) (next-eggs (rest loe)))]))
Now consider render-eggs:
(check-expect (render-eggs (cons (make-egg 100 50 25) (cons (make-egg 10 20 30) empty))) (place-image (rotate 25 YOSHI-EGG) 100 50 (place-image (rotate 30 YOSHI-EGG) 10 20 MTS)))
In this case the call to place-image is in the combination position (it gets the result of the natural recursion as an argument). Place-image also needs access to the results of multiple field selectors. So the place-image functionality goes into the helper and the helper is in combination position.
(define (render-eggs loe) (cond [(empty? loe) MTS] [else (place-egg (first loe) (render-eggs (rest loe)))]))
Be sure that you can see that place-egg consumes the result of the natural recursion, but next-egg does not. That happens because in tock-eggs we don't need to know anything about the details of the egg to know where to put it in the list. It always gets consed onto the front. So cons doesn't need to look inside the egg, it just puts it on the front.
But in render-eggs we do need to know the details of the egg to know where to put it on the image (on the result of the natural recursion). So place-egg needs to consume the egg as well as the result of the natural recursion.
The videos on edX cover this in great detail. Be sure to work through them and this example until you are confident you understand what happened here. Use the forums and/or office hours and DLC hours for extra help. Here also is another way of presenting this same difference:
(define (next-eggs loe) (cond [(empty? loe) empty] [else ;generic composition: cons ;egg specific contribution: uses x, y and r ;---> combination in list fn, contribution entirely in helper ;(cons (make-egg (egg-x (first loe)) ; (+ (egg-y (first loe)) FALL-SPEED) ; (+ (egg-r (first loe)) SPIN-SPEED)) (cons (next-egg (first loe)) (next-eggs (rest loe)))])) (define (render-eggs loe) (cond [(empty? loe) MTS] [else ;egg specific composition: place-image needs x, y ;egg specific contribution: uses r ;---> combination is in helper, also does contribution work ;(place-image (rotate (egg-r (first loe)) YOSHI-EGG) ; (egg-x (first loe)) ; (egg-y (first loe)) ; (render-eggs (rest loe))) (place-egg (first loe) (render-eggs (rest loe)))]))
Note that we are using single semi-colon comments because these are not the kind of comment that we would normally leave in code. They are temporary.
Be sure to complete the before lecture section of Lecture 8 before that lecture.