SICP. 2.2.4
2023-06-07 Wed

Exercise 2.44

Exercise:

Define the procedure up-split used by corner-split. It is similar to right-split, except that it switches the roles of below and beside.

Answer:

(define (up-split painter n)
  (if (= n 0)
      painter
      (let ((smaller (right-split painter (- n 1))))
        (below painter (beside smaller smaller)))))

Exercise 2.45

Exercise:

Right-split and up-split can be expressed as instances of a general splitting operation. Define a procedure split with the property that evaluating

(define right-split (split beside below))
(define up-split (split below beside))

produces procedures right-split and up-split with the same behaviors as the ones already defined.

Answer:

(define (split p1 p2)
  (lambda (painter n)
    (if (= n 0)
        painter
        (let ((smaller ((split p1 p2) painter
                        (- n 1))))
          (p1 painter
              (p2 smaller smaller))))))

Exercise 2.46

Exercise:

A two-dimensional vector v running from the origin to a point can be represented as a pair consisting of an x-coordinate and a y-coordinate. Implement a data abstraction for vectors by giving a constructor make-vect and corresponding selectors xcor-vect and ycor-vect. In terms of your selectors and constructor, implement procedures add-vect, sub-vect, and scale-vect that perform the operations vector addition, vector subtraction, and multiplying a vector by a scalar:

\((x_1, y_1) + (x_2, y_2) = (x_1 + x_2, y_1 + y_2)\),

\((x_1, y_1) - (x_2, y_2) = (x_1 - x_2, y_1 - y_2)\),

\(s \cdot (x, y) = (sx, sy)\).

Answer:

(define (make-vect xcor ycor)
  (cons xcor ycor))
;; alternatively:
;; (define make-vect cons)

(define (xcor-vect vect)
  (car vect))
;; alternatively:
;; (define xcor-vect car)

(define (ycor-vect vect)
  (cdr vect))
;; alternatively
;; (define ycor-vect cdr)

(define (add-vect v1 v2)
  (make-vect (+ (xcor-vect v1) (xcor-vect v2))
             (+ (ycor-vect v1) (ycor-vect v1))))

(define (sub-vect v1 v2)
  (make-vect (- (xcor-vect v1) (xcor-vect v2))
             (- (ycor-vect v1) (ycor-vect v2))))

(define (scale-vect vect s)
  (make-vect (* (xcor-vect vect) s)
             (* (ycor-vect vect) s)))

Exercise 2.47

Exercise:

Here are two possible constructors for frames:

(define (make-frame origin edge1 edge2)
  (list origin edge1 edge2))

(define (make-frame origin edge1 edge2)
  (cons origin (cons edge1 edge2)))

For each constructor supply the appropriate selectors to produce an implementation for frames.

Answer:

(define (make-frame origin edge1 edge2)
  (list origin edge1 edge2))

(define (origin-frame frame)
  (car frame))

(define (edge1-frame frame)
  (car (cdr frame)))

(define (edge2-frame frame)
  (car (cdr (cdr frame))))

Alternatively:

(define (make-frame origin edge1 edge2)
  (cons origin (cons edge1 edge2)))

(define (origin-frame frame)
  (car frame))

(define (edge1-frame frame)
  (car (cdr frame)))

(define (edge2-frame frame)
  (cdr (cdr frame)))

Exercise 2.48

Exercise:

A directed line segment in the plane can be represented as a pair of vectors—the vector running from the origin to the start-point of the segment, and the vector running from the origin to the end-point of the segment. Use your vector representation from Exercise 2.46 to define a representation for segments with a constructor make-segment and selectors start-segment and end-segment.

Answer:

(define (make-segment vector1 vector2)
  (cons vector1 vector2))

(define (start-segment segment)
  (car segment))

(define (end-segment segment)
  (cdr segment))

Exercise 2.49

Exercise:

Use segments->painter to define the following primitive painters:

  1. The painter that draws the outline of the designated frame.
  2. The painter that draws an “X” by connecting opposite corners of the frame.
  3. The painter that draws a diamond shape by connecting the midpoints of the sides of the frame.
  4. The wave painter.

Answer:

;; Painter that draws the outline of the frame
(segments->painter
 (list
  (make-segment (make-vect 0 0)
                (make-vect 0 1))
  (make-segment (make-vect 0 1)
                (make-vect 1 1))
  (make-segment (make-vect 1 1)
                (make-vect 1 0))
  (make-segment (make-vect 1 0)
                (make-vect 0 0))))
;; Painter that draws an ``X''
(segments->painter
 (list
  (make-segment (make-vect 0 0)
                (make-vect 1 1))
  (make-segment (make-vect 1 0)
                (make-vect 0 1))))
;; Painter that draws a diamond
(segments->painter
      (list
       (make-segment (make-vect 0.5 0)
                     (make-vect 0 0.5))
       (make-segment (make-vect 0 0.5)
                     (make-vect 0.5 1))
       (make-segment (make-vect 0.5 1)
                     (make-vect 1 0.5))
       (make-segment (make-vect 1 0.5)
                     (make-vect 0.5 0))))

Exercise 2.50

Exercise:

Define the transformation flip-horiz, which flips painters horizontally, and transformations that rotate painters counterclockwise by 180 degrees and 270 degrees.

Answer:

(define (flip-horiz painter)
  (transform-painter
   painter
   (make-vect 1.0 0.0)
   (make-vect 0.0 0.0)
   (make-vect 1.0 1.0)))
(define (rotate-cc-180 painter)
  (transform-painter
   painter
   (make-vect 1.0 1.0)
   (make-vect 0.0 1.0)
   (make-vect 1.0 0.0)))
(define (rotate-cc-270 painter)
  (transform-painter
   painter
   (make-vect 0.0 1.0)
   (make-vect 0.0 0.0)
   (make-vect 1.0 1.0)))

Exercise 2.51

Exercise:

Define the below operation for painters. Below takes two painters as arguments. The resulting painter, given a frame, draws with the first painter in the bottom of the frame and with the second painter in the top. Define below in two different ways—first by writing a procedure that is analogous to the beside procedure given above, and again in terms of beside and suitable rotation operations (from Exercise 2.50).

Answer:

(define (below2 p1 p2)
  (let ((paint-below (transform-painter
                      p1
                      (make-vect 0.0 0.0)
                      (make-vect 1.0 0.0)
                      (make-vect 0.0 0.5)))
        (paint-above (transform-painter
                      p2
                      (make-vect 0.0 0.5)
                      (make-vect 1.0 0.5)
                      (make-vect 0.0 1.0))))
    (lambda (frame)
      (paint-below frame)
      (paint-above frame))))

(paint (below2 einstein einstein))
(define (rotate-counterclock-90 painter)
  (transform-painter
   painter
   (make-vect 1.0 0.0)
   (make-vect 1.0 1.0)
   (make-vect 0.0 0.0)))

(define (rotate-clock-90 painter)
  (transform-painter
   painter
   (make-vect 0.0 1.0)
   (make-vect 0.0 0.0)
   (make-vect 1.0 1.0)))

(define (below3 p1 p2)
  (rotate-clock-90 (beside (rotate-counterclock-90 p1)
                           (rotate-counterclock-90 p2))))

(paint (below3 einstein einstein))

Exercise 2.52

Exercise:

Make changes to the square limit of wave shown in Figure 2.9 by working at each of the levels described above. In particular:

  1. Add some segments to the primitive wave painter of Exercise 2.49 (to add a smile, for example).
  2. Change the pattern constructed by corner-split (for example, by using only one copy of the up-split and right-split images instead of two).
  3. Modify the version of square-limit that uses square-of-four so as to assemble the corners in a different pattern. (For example, you might make the big Mr. Rogers look outward from each corner of the square.)

Answer:

;; Change at the level of wave: replace wave with the einstein painter
;; available in Racket's SICP picture language.

;; Change at the level of corner split: swap right-split and up-split:
(define (corner-split painter n)
  (if (= n 0)
      painter
      (let ((up (right-split painter (- n 1)))
            (right (up-split painter 
                             (- n 1))))
        (let ((top-left (beside up up))
              (bottom-right (below right 
                                   right))
              (corner (corner-split painter 
                                    (- n 1))))
          (beside (below painter top-left)
                  (below bottom-right 
                         corner))))))

;; Change at the level of square-limit: replace flip-vert with
;; flip-horiz:
(define (square-limit painter n)
  (let ((quarter (corner-split painter n)))
    (let ((half (beside (flip-horiz quarter)
                        quarter)))
      (below (flip-horiz half) half))))

(paint (square-limit einstein 3))

Send me an email for comments.

Created with Emacs 29.0.91 (Org mode 9.6.6)