바꾸기 mutation: 값이 아니라 물건으로 생각하기 값: 변하지 않는다 (define x 3): x는 정수값 3이다. (add1 x)은 4라는 값이다. 3이 변해서 4가 된것이 아니다. (add-element 1 S)는 S U{1} 인 집합이다. 집합 S가 변해서 1이 첨가된 집합이 되는 것이 아니다. 물건: 상태가 변한다 (add-element 1 S)는 S가 변해서 1이 첨가된 새로운 집합이 된다.
값 중심 vs 물건 중심 프로그래밍 값: 변하지 않는다 물건: 상태가 변한다 (add-element 1 S)는 S U{1} 인 집합이다. 집합 S가 변해서 1이 첨가된 집합이 되는 것이 아니다. 지금까지 이렇게 프로그램하는 것으로 은연중에 익혀왔습니다. 물건: 상태가 변한다 (add-element 1 S)는 S가 변해서 1이 첨가된 새로운 집합이 된다. 이렇게 프로그램하고 싶은 유혹이 있었을 것입니다.
값 중심 vs 물건 중심 프로그래밍 값중심 물건중심: “L을 바꿔서 L+R이되게” (define (append L R) (cond ((null? L) R) ((null? R) L) (else (cons (car L) (append (cdr L) R))) )) 물건중심: “L을 바꿔서 L+R이되게” (cond ((null? L) (make-L R; L)) (else (make-L’s cdr (append (cdr L) R); L))
바꿔!연산자들 mutators (1/3) (set! <id> <exp>) (define x 10) ... (+ x 1) ... (+ x 1) ... x의 유효범위내에서는 x는 항상 10. 그러나 이젠, (+ x 1) ... (set! x 9) ... (+ x 1) set!이후에는 x의 유효범위가 같지만 x가 9로 변해있다.
바꿔!연산자들 mutators (2/3) (set-car! <exp1> <exp2>) <exp1> 이 cons-cell이어야 한다 <exp1>의 car part가 <exp2>로 바뀐다. (define L ‘(1 2)) (set-car! L “kwang”) L ==> (“kwang” 2) (set-car! (cdr L) “teaches 102”) L ==> (“kwang” “teaches 102”) (set-car! (cdr L) ‘(“teaches” “102”)) L ==> (“kwang” (“teaches” “102”))
바꿔!연산자들 mutators (3/3) (set-cdr! <exp1> <exp2>) <exp1> 이 cons-cell이어야 한다 <exp1>의 cdr part가 <exp2>로 바뀐다. (define L ‘(1 2)) (set-cdr! L ‘(“kwang”)) L ==> (1 “kwang”) (set-cdr! (cdr L) “teaches 102”) L ==> (1 “kwang” . “teaches 102”) (set-cdr! (cdr L) ‘(“teaches” “102”)) L ==> (1 “kwang” “teaches” “102”)
바꿔!연습 1 (define x ‘(1 2)) (define y ‘(3 4)) (set-car! x y) followed by (set-cdr! x y) x ==> ((3 4) 3 4)
바꿔!연습 2 (define x ‘(1 2)) (define y ‘(3 4)) (set-car! x y) followed by (set-car! y x) x ==> (((…()…) 4) 2) ; has an abyss
바꿔!연습 3 (define x ‘(1)) (define y ‘(2)) (set-cdr! x y) x ==> (1 2) followed by (set-cdr! y x) x ==> (1 2 1 2 1 2 1 2 …) infinite list, a cycle
데이타구현: 값중심 vs 물건중심 예) 스택 stack empty: stk empty: stk push: stk * elmt -> void is-empty?: stk -> bool pop: stk -> elmt empty: stk push: stk * elmt -> stk is-empty?: stk -> bool pop: stk -> elmt * stk (define empty (cons nil nil)) (define (push s x) (let ((cell (cons x nil))) (set-cdr! cell (cdr s)) (set-cdr! s cell))) (define (is-empty? s) (null? (cdr s))) (define (pop s) (if (is-empty? s) (error) …)) (define empty ()) (define (push s x) (cons x s)) (define is-empty? null?) (define (pop s) (if (is-empty? s) (error) s)
바꿔!연산자를 이용한 물건중심구현 (1/2) 복잡하다: 프로그램짜기 어렵다 왜? 물건의 상태가 변하는 것을 추적하면서 프로그램해야. 왜? 물건이 어떻게 메모리에 구현되는지를 알아야: pointers, pointers, pointers… 왜? 예전엔 미처 생각못한 일이 벌어질 수 있다. ;; db is a list. (define (last-knowledge db) (cond ((null? db) ()) ((null? (cdr db)) (car db)) (else (last-knowledge (cdr db))))) ...;; happy programming, never imagine that db can be a cycle ...;; after 2 months, 30K lines of pgming, at a gloomy night (set-cdr! db bd) (set-cdr! bd db) ;; I need a cycle ...;; then this will kill me (last-knowledge db) ;; this never returns!
바꿔!연산자를 이용한 물건중심구현 (2/2) 필요하다: “칠판”이 필요하다 예) counter, db, 공용테이블, … 그런 물건이 간단하고 프로그램 전체적으로 그 갯수가 미리 정해져 있다면 (실행중에 계속 새롭게 만들어 지지 않고) 프로그램에 어려움없이 바꿔!연산자를 잘 이용할 수 있다.
물건중심의 프로그래밍 예: function-dispatch table ‘real ‘imag ‘mag ‘angle ‘rectangular real-r imag-r mag-r angle-r ‘polar real-p imag-p mag-p angle-p ‘xyz real-x imag-x mag-x angle-x (define (real c) ((dispatch (type c) ‘real) c))) (define (angle c) ((dispatch (type c) ‘angle) c)) (define (imag c) ((dispatch (type c) ‘imag) c)) (define (mag c) ((dispatch (type c) ‘mag) c))
층층이 속내용 감추기 Abstraction Hierarchy attach tags to data about types and reprsntns use dispatch tables for improved additivity add mul add-rational mul-rational add-complex mul-complex add-intvl mul-intvl real imag mag angle is-complex? … denom numer is-rational? … min max is-ntvl? … real-r imag-r … real-p iamg-p… pair representation pair representation rectangular representation polar representation