2008. 8. 5.

연습문제 2.77

그림 2.24는 Scheme 문으로는 다음과 같다.

(cons 'complex (cons 'rectangular (cons 3 4)))
-> (complex rectangular 3 . 4)

Louis Reasoner가 원한 (magnitude z)를 얻기 위해서는 실제로 다음과 같은 호출이 있어야한다.

(apply-generic 'magnitude z)

이전 챕터에서 apply-generic을 가져오면 다음과 같다.

(define (apply-generic op . args)
  (let ((type-tags (map type-tag args)))
    (let ((proc (get op type-tags)))
      (if proc
          (apply proc (map contents args))
          (error
            "No method for these types -- APPLY-GENERIC"
            (list op type-tags))))))

따라서 해당하는 형의 태그내에서 실제로 함수를 발견하지못했기때문에 에러가 발생한다.
apply-generic은 먼저 args의 형을 가져오고 다음에 해당하는 태그에 맞는 함수를 가져온다. 따라서 'complex에 대해 한번, 'magnitude에 대해 한번 수행한다.

연습문제 2.77

그림 2.24는 Scheme 문으로는 다음과 같다.

(cons 'complex (cons 'rectangular (cons 3 4)))
-> (complex rectangular 3 . 4)

Louis Reasoner가 원한 (magnitude z)를 얻기 위해서는 실제로 다음과 같은 호출이 있어야한다.

(apply-generic 'magnitude z)

이전 챕터에서 apply-generic을 가져오면 다음과 같다.

(define (apply-generic op . args)
  (let ((type-tags (map type-tag args)))
    (let ((proc (get op type-tags)))
      (if proc
          (apply proc (map contents args))
          (error
            "No method for these types -- APPLY-GENERIC"
            (list op type-tags))))))

따라서 해당하는 형의 태그내에서 실제로 함수를 발견하지못했기때문에 에러가 발생한다.
apply-generic은 먼저 args의 형을 가져오고 다음에 해당하는 태그에 맞는 함수를 가져온다. 따라서 'complex에 대해 한번, 'magnitude에 대해 한번 수행한다.

2008. 8. 4.

투명 필름문제 Scheme 답

문제는 http://codingdojo.metaschool.org/4893 에 있습니다.

해당하는 스킴 코드를 짜봤습니다.

입력부분은 그냥 panel을 리스트로 구성해서 넘겼고..
출력은 일단 리스트로 만들었으니 나중에 따로 출력부만 만들면 될 것 같습니다.

;; 점 표시..
(define (make-point x y)
  (list x y))

(define (get-x point)
  (car point))

(define (get-y point)
  (cadr point))

;; 라인 표시.
(define (make-line p1 p2)
  (if (< (get-x p1) (get-x p2))
      (list p1 p2)
      (list p2 p1)))

(define (get-left line)
  (car line))

(define (get-right line)
  (cadr line))

;; 패널 표시
(define (make-panel line transp)
  (list line transp))

(define (get-line panel)
  (car panel))

(define (get-transp panel)
  (cadr panel))



;; 예제 패널에서 x축 데이터만 가져오기
(define (get-x-from-panel panel)
  (let ((line-list (map (lambda (p) (get-line p)) panel)))
    (let ((left-point (map (lambda (l) (get-left l)) line-list))
          (right-point (map (lambda (l) (get-right l)) line-list)))
      (let ((left-x-point (map (lambda (p) (get-x p)) left-point))
            (right-x-point (map (lambda (p) (get-x p)) right-point)))
        (quicksort (union-set left-x-point right-x-point))))))

;; 0.0 부터 시작해서 각 x점마다 중간점을 이용해서 해당 점이 개별 패널이 들어있는지 찾기
(define (get-middle p1 p2)
  (/ (+ p1 p2) 2))



;; 특정 점이 패널에 속했는지 여부 알기..
(define (in-width x line)
  (let ((left-point (get-left line))
        (right-point (get-right line)))
    (let ((left-x (get-x left-point))
          (right-x (get-x right-point)))
      (and (<= left-x x)
           (>= right-x x)))))

;; 특정 점이 속하는 패널 값 가져오기
(define (get-transp-list x panel-list)
  (map (lambda (panel)
         (if (in-width x (get-line panel))
             (get-transp panel)
             0.0)) panel-list))

;; 리스트 값중 0.0이면 무시하고 나머지 값을 모두 곱하기
(define (product-transp transp-list)
  (if (null? transp-list)
      1
      (if (= 0 (car transp-list))
          (* 1 (product-transp (cdr transp-list)))
          (* 1 (car transp-list)
             (product-transp (cdr transp-list))))))

(define (quicksort lst)
  (if (null? lst)
      '()
      (let ((middle (car lst)))
        (if (< (length lst) 1)
            lst
            (append
             (quicksort (lessor_list lst middle))
             (cons middle (quicksort (larger_list lst middle))))))))

(define (length lst)
  (if (null? lst)
      0
      (+ 1 (length (cdr lst)))))

(define (nth n lst)
  (if (null? lst)
      '()
      (if (= n 0)
          (car lst)
          (nth (- n 1) (cdr lst)))))

(define (lessor_list lst value)
  (if (null? lst)
      '()
      (let ((item (car lst)))
        (cond ((< item value) (cons item (lessor_list (cdr lst) value)))
              (else
               (lessor_list (cdr lst) value))))))

(define (larger_list lst value)
  (if (null? lst)
      '()
      (let ((item (car lst)))
        (cond ((> item value) (cons item (larger_list (cdr lst) value)))
              (else
               (larger_list (cdr lst) value))))))


;; X축에 대해 sorted list에 넣기
(define (element-of-set? x set)
  (cond ((null? set) #f)
        ((< x (car set)) #f)
        ((= x (car set)) #t)
        (else
         (element-of-set? x (cdr set)))))
      
(define (adjoin-set x set)
  (if (null? set)
      (list x)
      (let ((first-item (car set)))
        (cond ((< x first-item) (cons x set))
              ((= x first-item) set)
              (else
               (adjoin-set x (cdr set)))))))

(define (union-set set1 set2)
  (cond ((and (null? set1) (null? set2)) '())
        ((null? set1) set2)
        ((null? set2) set1)
        (else
         (let ((item1 (car set1)) (item2 (car set2)))
           (cond ((= item1 item2) (cons item1 (union-set (cdr set1) (cdr set2))))
                 ((< item1 item2) (cons item1 (union-set (cdr set1) set2)))
                 (else (cons item2 (union-set set1 (cdr set2)))))))))


;; 예제 패널..
(define exam-panel
  (list
   (make-panel (make-line (make-point 2.0  2.0) (make-point  9.0  2.0))  0.9 )
   (make-panel (make-line (make-point 13.5  2.0) (make-point  4.0  8.5))  0.7 )
   (make-panel (make-line (make-point 17.0  10.0)  (make-point 7.0  8.5))  0.8 )))


;; 실제 투명값 구하는 부분..
(define (get-transp-in-panel panel)
  (let ((x-list (get-x-from-panel panel)))
    (let ((all-x-list (cons 0.0 x-list)))
      (define (i-g-t-i-p xlist)
        (if (< (length xlist) 2)
            (list (cons (car xlist) (cons 'inf (list 1.0))))
            (let ((left (car xlist))
                  (right (cadr xlist)))
              (cons (cons left (cons right (list (product-transp (get-transp-list (get-middle left right) panel)))))
                    (i-g-t-i-p (cdr xlist))))))
      (i-g-t-i-p all-x-list))))


투명 필름문제 Scheme 답

문제는 http://codingdojo.metaschool.org/4893 에 있습니다.

해당하는 스킴 코드를 짜봤습니다.

입력부분은 그냥 panel을 리스트로 구성해서 넘겼고..
출력은 일단 리스트로 만들었으니 나중에 따로 출력부만 만들면 될 것 같습니다.

;; 점 표시..
(define (make-point x y)
  (list x y))

(define (get-x point)
  (car point))

(define (get-y point)
  (cadr point))

;; 라인 표시.
(define (make-line p1 p2)
  (if (< (get-x p1) (get-x p2))
      (list p1 p2)
      (list p2 p1)))

(define (get-left line)
  (car line))

(define (get-right line)
  (cadr line))

;; 패널 표시
(define (make-panel line transp)
  (list line transp))

(define (get-line panel)
  (car panel))

(define (get-transp panel)
  (cadr panel))



;; 예제 패널에서 x축 데이터만 가져오기
(define (get-x-from-panel panel)
  (let ((line-list (map (lambda (p) (get-line p)) panel)))
    (let ((left-point (map (lambda (l) (get-left l)) line-list))
          (right-point (map (lambda (l) (get-right l)) line-list)))
      (let ((left-x-point (map (lambda (p) (get-x p)) left-point))
            (right-x-point (map (lambda (p) (get-x p)) right-point)))
        (quicksort (union-set left-x-point right-x-point))))))

;; 0.0 부터 시작해서 각 x점마다 중간점을 이용해서 해당 점이 개별 패널이 들어있는지 찾기
(define (get-middle p1 p2)
  (/ (+ p1 p2) 2))



;; 특정 점이 패널에 속했는지 여부 알기..
(define (in-width x line)
  (let ((left-point (get-left line))
        (right-point (get-right line)))
    (let ((left-x (get-x left-point))
          (right-x (get-x right-point)))
      (and (<= left-x x)
           (>= right-x x)))))

;; 특정 점이 속하는 패널 값 가져오기
(define (get-transp-list x panel-list)
  (map (lambda (panel)
         (if (in-width x (get-line panel))
             (get-transp panel)
             0.0)) panel-list))

;; 리스트 값중 0.0이면 무시하고 나머지 값을 모두 곱하기
(define (product-transp transp-list)
  (if (null? transp-list)
      1
      (if (= 0 (car transp-list))
          (* 1 (product-transp (cdr transp-list)))
          (* 1 (car transp-list)
             (product-transp (cdr transp-list))))))

(define (quicksort lst)
  (if (null? lst)
      '()
      (let ((middle (car lst)))
        (if (< (length lst) 1)
            lst
            (append
             (quicksort (lessor_list lst middle))
             (cons middle (quicksort (larger_list lst middle))))))))

(define (length lst)
  (if (null? lst)
      0
      (+ 1 (length (cdr lst)))))

(define (nth n lst)
  (if (null? lst)
      '()
      (if (= n 0)
          (car lst)
          (nth (- n 1) (cdr lst)))))

(define (lessor_list lst value)
  (if (null? lst)
      '()
      (let ((item (car lst)))
        (cond ((< item value) (cons item (lessor_list (cdr lst) value)))
              (else
               (lessor_list (cdr lst) value))))))

(define (larger_list lst value)
  (if (null? lst)
      '()
      (let ((item (car lst)))
        (cond ((> item value) (cons item (larger_list (cdr lst) value)))
              (else
               (larger_list (cdr lst) value))))))


;; X축에 대해 sorted list에 넣기
(define (element-of-set? x set)
  (cond ((null? set) #f)
        ((< x (car set)) #f)
        ((= x (car set)) #t)
        (else
         (element-of-set? x (cdr set)))))
      
(define (adjoin-set x set)
  (if (null? set)
      (list x)
      (let ((first-item (car set)))
        (cond ((< x first-item) (cons x set))
              ((= x first-item) set)
              (else
               (adjoin-set x (cdr set)))))))

(define (union-set set1 set2)
  (cond ((and (null? set1) (null? set2)) '())
        ((null? set1) set2)
        ((null? set2) set1)
        (else
         (let ((item1 (car set1)) (item2 (car set2)))
           (cond ((= item1 item2) (cons item1 (union-set (cdr set1) (cdr set2))))
                 ((< item1 item2) (cons item1 (union-set (cdr set1) set2)))
                 (else (cons item2 (union-set set1 (cdr set2)))))))))


;; 예제 패널..
(define exam-panel
  (list
   (make-panel (make-line (make-point 2.0  2.0) (make-point  9.0  2.0))  0.9 )
   (make-panel (make-line (make-point 13.5  2.0) (make-point  4.0  8.5))  0.7 )
   (make-panel (make-line (make-point 17.0  10.0)  (make-point 7.0  8.5))  0.8 )))


;; 실제 투명값 구하는 부분..
(define (get-transp-in-panel panel)
  (let ((x-list (get-x-from-panel panel)))
    (let ((all-x-list (cons 0.0 x-list)))
      (define (i-g-t-i-p xlist)
        (if (< (length xlist) 2)
            (list (cons (car xlist) (cons 'inf (list 1.0))))
            (let ((left (car xlist))
                  (right (cadr xlist)))
              (cons (cons left (cons right (list (product-transp (get-transp-list (get-middle left right) panel)))))
                    (i-g-t-i-p (cdr xlist))))))
      (i-g-t-i-p all-x-list))))


연습문제 2.76

일을 직접 나눠 맡기는 방식 : 새로운 타입이 추가될 때마다 해당 타입에 맞는 고유한 이름을 정의해서 정의해야한다.

데이터 중심 방식 : 새로운 타입이 추가될 때에는 연산에 따라 묶음(Package)을 구성하고, 이를 연산 도표에 적용시켜주면 된다.

메시지 패싱 방식 : 새로운 타입이 추가될 때에는 타입에 해당하는 대표 함수를 정의하면 된다.

새 로운 데이터 타입을 집어넣어야할 일이 많다면 데이터 중심 방식이나 메시지 패싱 방식 모두 유효한 답이 된다. 새로운 연산이 증가되는 경우, 데이터 중심 방식에서는 기존의 연산 도표에 해당하는 연산을 정의해넣으면 되지만, 메시지 패싱 방식에서는 실제 정의를 변경해야한다. 이는 호불호가 갈리는 문제인데, 패키지안에 모든 내용을 넣는 경우에는 메세지 패싱 방식이나 데이터 중심 방식 모두 유지 보수 측면에서는 큰 차이가 나지는 않는다고 본다.

연습문제 2.76

일을 직접 나눠 맡기는 방식 : 새로운 타입이 추가될 때마다 해당 타입에 맞는 고유한 이름을 정의해서 정의해야한다.

데이터 중심 방식 : 새로운 타입이 추가될 때에는 연산에 따라 묶음(Package)을 구성하고, 이를 연산 도표에 적용시켜주면 된다.

메시지 패싱 방식 : 새로운 타입이 추가될 때에는 타입에 해당하는 대표 함수를 정의하면 된다.

새 로운 데이터 타입을 집어넣어야할 일이 많다면 데이터 중심 방식이나 메시지 패싱 방식 모두 유효한 답이 된다. 새로운 연산이 증가되는 경우, 데이터 중심 방식에서는 기존의 연산 도표에 해당하는 연산을 정의해넣으면 되지만, 메시지 패싱 방식에서는 실제 정의를 변경해야한다. 이는 호불호가 갈리는 문제인데, 패키지안에 모든 내용을 넣는 경우에는 메세지 패싱 방식이나 데이터 중심 방식 모두 유지 보수 측면에서는 큰 차이가 나지는 않는다고 본다.

연습문제 2.75

(define (make-from-mag-ang x y)
  (define (dispatch op)
    (cond ((eq? op 'magnitude) x)
          ((eq? op 'angle) y)
          ((eq? op 'real-part)
           (* x (cos y)))
          ((eq? op 'imag-part)
           (* y (sin y)))
          (else
           (error "Unknow op -- MAKE-FROM-MAG-ANG" op))))
  dispatch)