Functional Problem Solving (CSC 151 2016S) : EBoards

CSC151.02 2016S, Review Session 5 (2016-02-25)


Thank you to the students who showed up so that we get a review session that other students can read over later.

Overview

The Quiz

Topics

Types of questions

Your Questions

Please talk more about map. (x2)

Scheme provides "lists", which are ordered collections of values.

    > (list 1 2 3)
    '(1 2 3)

Right now, we use lists as collections of drawings that we systematically
alter to make more interesting drawings.

map is our primary technique for making new lists from old

(map fun lst) -> builds a new list by applying fun to each element of the original list.

> (define ith-drawing
    (lambda (i)
      (hshift-drawing 
       (* i 3)
       (vshift-drawing 
        (* i i)
        (scale-drawing i drawing-unit-circle)))))

> (image-show (drawing->image (ith-drawing 10) 200 200))
4
> (image-show (drawing->image (drawing-compose
                               (map ith-drawing (list 5 6 8 10 11)))
                              200 200))
5
> (image-show (drawing->image (drawing-compose
                               (map ith-drawing (iota 11)))
                              200 200))
. . lib/gigls/image.rkt:920:19: image-select-ellipse!: width and height must be at least 1
  in (image-select-ellipse! 6 2 0 0 0 0)
> (image-show (drawing->image (drawing-compose
                               (map ith-drawing (cdr (iota 11))))
                              200 200))
7
> (define nums (map increment (iota 11)))
> (image-show (drawing->image (drawing-compose
                               (map ith-drawing nums))
                              200 200))
8

Moral: map takes a list and makes a new list.

Can map work with multiple lists?

Yes, as long as you have a multi-parameter function.

> (map + (list 3 1 5) (list 2 5 2))
'(5 6 7)
> (map + (list 3 1 5) (list 2 5 2 1))
. . map: all lists must have same size; arguments were: # '(3 1 5) '(2 5 2 1)

Please talk more about tests.

We like to pretend that we are scientists, and we know that tests are part of science.

If this procedure works correctly, it will give this output from this input. (Try lots of different input/output pairs.)

Example: If irgb-redder is supposed to make colors redder, the red component if (irgb-redder (irgb 0 0 0)) should be greater than the red component of (irgb 0 0 0).

We express the tests in a formal language

     (check-true (> (irgb-red (irgb-redder (irgb 0 0 0)))
                    (irgb-red (irgb 0 0 0))))

Can you create generalized tests?

    (define check-redder
      (lambda (color)
        (check-true (> (irgb-red (irgb-redder color))
                       (irgb-red color)))))
    (check-redder (irgb 0 0 0))
    (check-redder (irgb 128 128 128))
    (check-redder (irgb 0 255 0))

    > (check-redder (irgb 255 255 255))
    --------------------
    FAILURE
    name:       check-true
    location:   (unsaved-editor322 33 12 1089 91)
    expression: (check-true (> (irgb-red (irgb-redder color)) (irgb-red color)))
    params:     (#f)

Hmmm ... either our irgb-redder is wrong, our test is wrong, or both.

Where do test-case and test-suite come in?

The checks are run immediately.

Sometimes we want to make tests to run later.

test-suite creates a set of tests you can run later.

> (define simple-red-tests
    (test-suite "Tests of irgb-redder"
                (check-redder (irgb 0 0 0))
                (check-redder (irgb 128 128 128))))
> (run-tests simple-red-tests)
2 success(es) 0 failure(s) 0 error(s) 2 test(s) run
0

It also gives better reporting.

test-case is somewhere in the middle. It's a way to group related tests together.

The strings are there for when a test fails, since they tell you what test failed.

Sample Quiz Questions

Draw the Picture

Consider the following set of instructions

(define d1 (scale-drawing 20 drawing-unit-circle))
(define d2 (hshift-drawing 10 (vshift-drawing 20 d1)))
(define d3 (recolor-drawing "red" (drawing-group d1 d2)))
(define d4 (vshift-drawing 10 d2))
(image-show (drawing->image (drawing group d4 d3) 100 100))

Sketch the drawing that results. You should assume that in any group of drawings, the second is drawn over the first.

Interpret the Picture

Recall that the smaller-right-neighbor procedure makes a copy of a drawing immediately to the right of the first drawing, scaled by 75% and with the top edge.

Stu and Dent type the following command

(image-show (drawing->image (drawing group d1 (smaller-right-neighbor d1))
                            150 100))

They are surprised at what they see, which I've sketched in ASCII art as follows.

+--------------------------------------+-------+
|                                      |       |
|                                      |       |
|                                      |       |
|               +----------------------+       |
|               |                              |
|               |                              |
|               |                              |
+---------------+                              |
|                                              |
|                                              |
|                                              |
|                                              |
|                                              |
|                                              |
+----------------------------------------------+

The upper-left rectangle appears to be 50x50. The thinner rectangle to the right appears to be 75x25. Assuming the smaller-right-neighbor procedure works correctly. Explain what d1 is.

A Solution

If d1 is a 100x100 square, centered at (0,0), only the lower-right-hand corner appears, so it looks like a 50x50 square. The neighbor is 75x75, with top at -50 and left at 50, so only the bottom 1/3 appears.

Interpret the Code

Give the output of the following

> (map odd? (iota 6))
> (map square (iota 6))
> (map (o odd? square) (iota 6))
> (map + (iota 6) (iota 6))

Write a procedure

Without using if or cond, write a procedure, (large-odd? i), that takes an integer as input and returns true if the integer is greater than 100 and odd, and false othrwise.

Write another procedure

Write a procedure, (distinct color), that takes an integer-encoded RGB color as input and returns true if no two components are within 16 of each other and false otherwise.

Write another procedure

Write a procedure, (purplish color), that takes an integer-encoded RGB color as input and returns true if each of the red and blue components is greater than the green component and the the red and blue components are within 32 of each other.

Write a procedure

Write a procedure, (extremes list-of-values) that takes a list of integers as input and returns a list of integers as output in which the ith element of the output is 0 if the corresponding element of the input is less than 128, and 255 if the corresponding element of the input is greater than 127.

> (extremes (list 100 200 50 86 200 -50 1000))
'(0 255 0 0 255 0 255)

A Solution

We are going from one list to another, so we will need map.

(define extremes
  (lambda (lst)
    (map ??? lst)))

What does ??? do? A procedure that makes numbers less than 128 go to 0 and numbers greater than 127 go to 255.

(define ???
  (lambda (i)
    (if (< i 128)
        0
        (if (> i 127)
            255
            'oh))))

Sam would prefer

(define ???
  (lambda (i)
    (if (< i 128)
        0
        255)))

Sam would also prefer a better name than ???.

Write another procedure

Write a procedure, (dominant color), that takes an integer-encoded RGB color as input and returns (irgb 255 0 0) if the red component dominates, (irgb 0 255 0) if the green component dominates, (irgb 0 0 255) is blue component dominates, and (irgb 128 128 128) if no component dominates.

Write a procedure

Write a new predicate, (image-contains-rectangle? img left top width height), that determines whether some of the given rectangle is likely to be within the given image.

A Solution

Let's think about when we can and cannot see a rectangle within the image. We know the width and height of the image, and the left, top, width, and height of the rectangle.

We've written a procedure, simple-center-x, that tells you where the x coordinate of the center is. You can check with the center (or some variant thereof) is within the horizontal bounds.

(define image-contains-center-of-rectangle
  (lambda (img rect)
    (and (and (<= 0 (simple-center-x rect))
              (< (simple-center-x rect) (drawing-width img)))
         (and (<= 0 (simple-center-y rect))
              (< (simple-center-y rect) (drawing-height img))))))

We can ask something similar about the left, the right, the top, and the bottom

(define image-contains-part-of-rectangle
  (lambda (img left top width height)
    (and
         ;Horizonatal
         (or
             ; left
             (and (<= 0 left)
                  (< left (drawing-width img)))
             ; right
             (and (<= 0 (+ left width))
                  (< (+ left width) (drawing-width img))))
         ; Vertical
         (or
             ; top
             (and (<= 0 top)
                  (< top (drawing-height img)))
             ; bottom
             (and (<= 0 (+ top height))
                  (< (+ top height) (drawing-height img)))))))

Write a procedure

Write a procedure, (square-the-circle drawing), that takes a drawing of a circle as input and creates a new drawing of a rectangle of the same width, height, and position.

Find the Drawing

Taylor and Jordan know that when they scale a drawing, not only do the width and height change, but also the left and top. Hence, they are surprised to find that no errors are reported by the following tests.

(check-= (drawing-left d15) (drawing-left (scale-drawing 2 d15)) .001)
(check-= (drawing-top d15) (drawing-top (scale-drawing 1/2 d15)) .001)

Describe a drawing, d15, for which these tests will succeed.

Additional Questions