SICP 연습문제 2.51 친절한 풀이

문제

페인터 연산 below를 정의하라. below는 페인터 두 개를 인자로 받아서 첫 번째 페인터는 틀 아래쪽에, 두 번째 페인터는 틀 위쪽에 그림을 그리도록 합쳐진 페인터를 내놓는다. below 프로시저를 두 가지 방법으로 정의해 보라. 하나는 위에서 정의한 beside 프로시저와 비슷하게, 다른 하나는 beside와 (연습문제 2.50에서 정의한) 돌리는 연산을 써서 정의해 보라.

문제로 부터 얻은 것

tansform-painter를 쓰면, 범용적인 그림 변환이 가능하지만
가끔은 미리 만들어 놓은 프로시저를 조합해서 표현을 간결하게 하는 것도 좋다는 생각이 들었습니다.

문제풀이

책의 설명을 잘 이해했다면 transform-painter의 사용은 그렇게 어렵지 않을 것 같습니다. 이 프로시저도 기본적으로 패키지 안에 내장된 프로시저이니 따로 구현할 필요 없습니다.

#lang sicp 
(#%require sicp-pict)

a. split-point

책에서 설명한 beside 프로시저는 다음과 같습니다. 이를 참고해서 below 프로시저를 만들어 보겠습니다.

(define (beside painter1 painter2)
(let ((split-point (vect 0.5 0.0)))
(let ((paint-left
(transform-painter painter1
(vect 0.0 0.0)
split-point
(vect 0.0 1.0)))
(paint-right
(transform-painter painter2
split-point
(vect 1.0 0.0)
(vect 0.5 1.0))))
(lambda (frame)
(paint-left frame)
(paint-right frame)))))



transform-painter의 원리만 안다면 그렇게 어려운 문제는 아닙니다.

(define (below painter1 painter2)
(let ((split-point (vect 0.0 0.5)))
(let ((paint-down
(transform-painter painter1
(vect 0.0 0.0)
(vect 1.0 0.0)
split-point))
(paint-up
(transform-painter painter2
split-point
(vect 1.0 0.5)
(vect 0.0 1.0))))
(lambda (frame)
(paint-down frame)
(paint-up frame)))))

층으로 나뉜 아인슈타인 - 1



b. 돌리는 연산

연습문제 2.50의 돌리는 프로시저는 다음과 같습니다.

(define (rotate180 painter)
(transform-painter painter
(vect 1.0 1.0)
(vect 0.0 1.0)
(vect 1.0 0.0)))

(define (rotate270 painter)
(transform-painter painter
(vect 0.0 1.0)
(vect 1.0 1.0)
(vect 0.0 0.0)))




생각하는 과정이 재밌는 문제였습니다. beside를 써서 위 아래로 그림을 나누기 위해서는 우선 옆으로 나란히 있는 그림을 만든 뒤에 반시계 방향으로 90도 회전하면 됩니다. 그 전에 미리 양 옆의 그림들을 방향에 맞게 회전시켜 놓으면 쉽게 문제를 풀 수 있습니다.

(define (below painter1 painter2)
(let ((p1 (rotate270 painter1))
(p2 (rotate270 painter2)))
(rotate90 (beside p1 p2))))

층으로 나뉜 아인슈타인 - 2



읽어주셔서 감사합니다.