CSC151.02 2016S, Review Session 3 (2016-02-11) ============================================== _Thank you to the students who showed up so that we get a review session that other students can read over later._ _Overview_ * Your exam questions. * Quiz topics and structure. * Your questions. * Sample quiz questions. * More questions. Your Exam Questions ------------------- _None yet._ _Reminders: It's good to ask questions. It's good to look at the exam asap._ Quiz Topics and Structure ------------------------- Topics * Defining procedures with `section` * Procedures with `lambda` * Documentation * Order-of-evaluation * Simple output (particularly annotating procedures) Form * Some reading ("what does this code do?") * Give output * Write documentation * Some writing ("write a procedure that ...") Your Questions -------------- 'll try to gather them all and then answer them. _Can we talk a bit more about `section`?_ > `section` is a procedure that makes procedures. One of three mechanisms we currently know (the others are `compose` and `lambda`). > Like `compose`, `section` makes procedures only from existing procedures. > We make new procedures by "filling in" one or more parameters of the existing procedure. > A few examples ; Know (expt base power) and computes base*base*base*...base ; power times. (define square (section expt <> 2)) (define three-to-the (section expt 3 <>)) > Note: `section` is part of the gigls library. > You can have more than one "open space" (define stupid (section - <> 3 <>)) > (define stupid (section - <> 3 <>)) > (stupid 2) . . stupid: arity mismatch; the expected number of arguments does not match the given number expected: 2 given: 1 arguments...: 2 > (stupid 5 2) 0 > ; That's 5 - 3 - 2 (define rg (section irgb <> <> 0)) > (rg 200 100) 13132800 > (irgb->string (rg 200 100)) "200/100/0" > We do not write an open paren before the procedure name in `section` (nor in `compose`, nor in `image-variant`, nor in others that we'll see soon). _Are there things we can do with `section` that we can't do with `lambda`, and vice versa?_ > Anything you can do with `section`, you can do with lambda. It's just more text. (Stylistic, rather than preferences.) (define rg (lambda (r g) (irgb r g 0))) > There are many things you can do with lambda that you can't do with `section`. (define pointless (lambda (x) (* x (+ x x)))) > `lambda`, unlike `section`, is a standard part of Scheme (core to Scheme) > We tend to use `lambda` except when `section` and `compose` make our code more concise (or more readable). Sample Quiz Questions --------------------- 1. Go to 2. Click on "CSC 151" 3. Click on "Current: Eboard" ### Understand (and document) image code Consider the following procedure (define fun (compose image-show (section image-variant (image-load "/home/rebelsky/Desktop/kitten.jpg") <>))) Write the first four P's of the six-P style documentation for this procedure. #### A Solution ;;; Procedure: ;;; ;;; Parameters: ;;; ;;; Purpose: ;;; ;;; Produces: ;;; ### Order of Evaluation Consider the following procedures (define yield (lambda (val) (display " yields ") (display val) (newline) val)) (define add (lambda (x y) (display x) (display " plus ") (display y) (yield (+ x y)))) (define square (lambda (x) (display x) (display " squared ") (yield (* x x)))) What output and result should you get for each of the following expressions? (add 2 3) (add x y) (add (square 2) (square 3)) (square (add 2 3)) (add (square 2) (square (square 3))) ### Averaging Colors Write `(irgb-average color1 color2)`, which averages the red, green, and blue components of `color` and `color2`. (define irgb-average (lambda (color1 color2) ....)) ### Annotating Code Consider the following procedure, which computes the largest of the three components of an integer-encoded RGB color. (define irgb-max (lambda (color) (max (irgb-red color) (irgb-green color) (irgb-blue color)))) Write a procedure, `irgb-max_*`, which takes the same input as `irgb-max`, generates the same output as `irgb-max`, and also prints a short message describing these input and output. You may use `display` and `yield` in your instructions. ### Using Annotated Code Consider the following two procedures (define f1 (lambda (color) (irgb (* (irgb-red color) (quotient (irgb-red color) (irgb-max_* color))) (* (irgb-green color) (quotient (irgb-green color) (irgb-max_* color))) (* (irgb-blue color) (quotient (irgb-blue color) (irgb-max_* color)))))) (define f2 (lambda (color) (f2-helper color (irgb-max_* color)))) (define f2-helper (lambda (color cmax) (irgb (* (irgb-red color) (quotient (irgb-red color) cmax)) (* (irgb-green color) (quotient (irgb-green color) cmax)) (* (irgb-blue color) (quotient (irgb-blue color) cmax)) We should get the same return value from `f1` and `f2`. But will we see the same output (generated by `irgb-max_*`)? Why or why not? ### Making colors more cyan Taylor and Jordan have decided to write a procedure that makes colors more like cyan. They call it `cyanide`. (Don't blame me; it's their idea.) `(cyanide color)` should produce a new color in which the red component decreases by 16 (or to 0, if the component is less than 16), the blue component increases by 16 (or to 255, if the component is more than 239), and the green component also increases by 16 (or to 255, if the component is more than 239). Without using `lambda`, write `cyanide`. You will likely need to use `section` and `compose`. p.s. Here's the 6P-style documentation. ;;; Procedure: ;;; cyanide ;;; Parameters: ;;; color, an integer-encoded RGB color ;;; Purpose: ;;; Make color look more like "cyan" ;;; Produces: ;;; poisoned, an integer-encoded RGB color ;;; Preconditions: ;;; [No additional] ;;; Postconditions: ;;; (irgb-red poisoned) = (max 0 (- (irgb-red color) 16)) ;;; (irgb-green poisoned) = (min 255 (+ (irgb-green color) 16)) ;;; (irgb-blue poisoned) = (min 255 (+ (irgb-blue color) 16)) And here's an alternate postcondition ;;; Postconditions: ;;; If (irgb-red color) >= 16 ;;; (irgb-red poisoned) = (- (irgb-red color) 16) ;;; If (irgb-red color) < 16 ;;; (irgb-red poisoned) = 0 ;;; If (irgb-green poisoned) <= 239 ;;; (irgb-green poisoned) = (+ (irgb-green color) 16) ;;; If (irgb-green poisoned) > 239 ;;; (irgb-green poisoned) = 255 ;;; If (irgb-blue poisoned) <= 239 ;;; (irgb-blue poisoned) = (+ (irgb-blue color) 16) ;;; If (irgb-blue poisoned) > 239 ;;; (irgb-blue poisoned) = 255 #### A Solution ; Three tasks: ; Subtract 16 from the red component. ; (section irgb-subtract <> (irgb 32 0 0)) ; Add 16 to the green component. ; (section irgb-add <> (irgb 0 16 0)) ; Add 16 to the blue component. ; (section irgb-add <> (irgb 0 0 16)) (define cyanide (compose (section irgb-subtract <> (irgb 32 0 0)) (section irgb-add <> (irgb 0 16 0)) (section irgb-add <> (irgb 0 0 16)))) #### Another solution (define cyanide (compose (section irgb-subtract <> (irgb 32 0 0)) (section irgb-add <> (irgb 0 16 16)))) #### And nother solution (define cyanide (compose irgb-greener irgb-bluer irgb-darker)) This isn't as good, because a blue component of 5 gets turned into 32 rather than 21. But life is imperfect. ### Code Reading What does the following procedure do? (define c (compose (section min 100 <>) (section max 0 <>))) What does the following procedure do? (define d (compose (section max 100 <>) (section min 0 <>))) #### A Solution `(section max 0 <>)` computes the larger of its parameter and 0. Positive numbers stay positive. Negative numbers become 0. `(section min 100 <>)` computes the smaller of its parameter and 100. Numbers below 100 stay the same. Note ---- Email me questions and I will respond as quickly and in as much detail as I can. Enjoy the lovely sunny day. More of Your Questions ---------------------- _Why do we have `val` as the last element of `yield`?_ (define f1 (lambda (x) 1 2 3)) > (f1 7) 3 ; Scheme gives you the *last* value computed in a procedure if there ; are a series of computations (define f2 (lambda (x) (display x) (newline) 2 3)) > (f2 7) 7 ; purple to indicate "displayed" 3 ; blue to indicate "returned/computed" > (+ 1 (f2 7)) 7 ; purple to indicate "displayed" 4 ; blue to indicate "returned/computed" (define f3 (lambda (x) (display x) (newline))) > (f3 7) 7 ; purple to indicate "displayed" > (+ 1 (f3 7)) ; Error! Can't add 1 to # > (+ 1 (newline)) ; Error! Can't add 1 to # > (+ 1 (display x)) ; Error! Can't add 1 to # (define yield (lambda (val) (display " yields ") (display val) (newline) val)) ; Now the calling procedure can use `val`. ; yield is like `f3` but with `val` at the end. _Why do we have the newline?_ > It means that the next thing we display will be on the next line. _How do we transform colors without using `lambda`?_ > Two approaches. > Using compose and existing one-parameter procedures. > E.g., to reduce the red component by 32 ... we know how to increemnt the red component by 32 (`irgb-redder`), but that's backwards. What else would help? We know how to "invert" the values in a color (`irgb-complement`). Theory: Invert, increment by 32, and invert, we've effectively decremented. > Solution `(define irgb-less-red (compose irgb-complement irgb-redder irgb-complement))` > We also have some useful two-parameter procedures. `irgb-add` and `irgb-subtract` might be useful. (Component-wise addition or subtraction.) > `(define irgb-less-red (section irgb-subtract <> (irgb 32 0 0)))` > That will subtract 32 from the red, 0 from the green, 0 from the blue.