레이블이 SICP인 게시물을 표시합니다. 모든 게시물 표시
레이블이 SICP인 게시물을 표시합니다. 모든 게시물 표시

2009. 5. 11.

MIT에서 Scheme대신 Python으로 이전한 이유

전산쪽에서 근무하는 사람이라면 한번쯤 맞닥뜨리게될 책이 SICP이다.
이 책은 EE/CS(Eletrical Enginerring / Computer Science) 부문에서 1학년을 대상으로하는 교재였다. 이 기본 교재가 사용된 커리큘럼이 6.001 이었는데 이제는 6.01로 변경되면서 Python을 이용하고 있다.

이에 대해서 많은 이야기들이 있었지만, 최근 한 블로그에서 그에 관한 글이 실렸다.

거기서 한 부분을 살짝 발췌해보았다.

However, nowadays, a real engineer is given a big software library,with a 300-page manual that’s full of errors.  He’s also given a robot,whose exact behavior is extremely hard to characterize (what happenswhen a wheel slips?). The engineer must learn to perform scientificexperiments to find out how the software and hardware actually work, atleast enough to accomplish the job at hand.  Gerry pointed out that wemay not like it this way (”because we’re old fogies”), but that’s theway it is, and M.I.T. has to take that into account.


오늘 날, 실제 공학자는 300페이지에 달하는 에러투성이 메뉴얼이 포함된 방대한 소프트웨어 라이브러리를 제공받는다.또한,행동양식을 정확히 규정하기 어려운 로봇을  추가로 제공받는다. 공학자는 최소한 작업을 자유자재로 수행하기위해서는, 소프트웨어와 하드웨어가 실제로 어떻게 동작하는지 알아내기위한 과학적인 실험을 수행하는 법을 익혀야한다. Gerry는 우리가 이런 방식을 좋아하지 않겠지만, 현실이 그렇다는 것을 지적했고, MIT는 이를 고려한 것이다.

모든 것이 간단하고 분명했던 예전에 비해서, 현재 기술자들이 마주하는 현실은 확실히 복잡하고, 예측불가능하며, 하나의 완벽한 원칙을 통한 방식보다는 시행착오를 거쳐서 얻는 편이 더 간단한 시대가 되었다.
Scheme 이 만들어질 당시에는 정확힌 원칙을 토대로 만들어진 조각들을 하나하나 붙여서 만들면, 그것이 바로 솔루션이 되는 시대였다. 하지만, 시스템이 고도화되었고, 수많은 데이터들과, 복잡성이 자리를 잡은 시대에는, 한 사람의 프로그래머가 모든 시스템을 구성할 수 있는 시대와는 작별을 고해야했다.

다양한 방식의 라이브러리와 환경을 통합해나가야하는 상황에서 Scheme이 보여주었던 방식으로는 한계에 다달은 모양이다. 그 와중에 선택된 것이 Python 이다. 이유는 모르겠지만.. 아마도 커리큘럼 구성진이 실용적이면서도, 우아한 문법, 잘 정리된 라이브러리등에 점수를 주었는지도 모른다.

어쨌거나 6.001 이 더이상 유효한 커리큘럼이 아니라니 무척이나 아쉽다. 마이너한 언어를 다루는 사람에게는 더더욱 그렇다.. 음냠..

PS> 하지만 나처럼 혼자서 개발하는 사람에게는 그냥 그런가보다하는 생각뿐.... Python도 어느 정도 다루긴 하는데... 그놈의 탭인덴테이션은 내 취향이 아니라는 문제가... 그래서 Perl 을 계속하나부다...

2008. 9. 2.

연습문제 4.6


(define (let? exp)
(tagged-list? exp 'let))

(define (let-body exp)
(caddr exp))

(define (let-vars exp)
(let ((var-exp-list (cadr exp)))
(map car var-exp-list)))

(define (let-exps exp)
(let ((var-exp-list (cadr exp)))
(map cadr var-exp-list)))

(define (let->combination exp)
(cons
(make-lambda (let-vars exp)
(let-body exp))
(let-exps exp)))


연습문제 4.4

<blockquote>(define (eval-and exp env)
(if (null? exp)
#t
(let ((test (car exp)))
(if (eval test)
(eval-and (cdr exp) env)
#f))))

(define (eval-or exp env)
(if (null? exp)
#f
(let ((test (car exp)))
(if (eval test)
#t
(eval-or (cdr exp) env)))))

(define (and? exp)
(tagged-list? exp 'and))

(define (or? exp)
(tagged-list? exp 'or))
</blockquote>


좀 아리까리함..

연습문제 4.3

(define eval-table (make-table))
(define get (eval-table 'lookup-proc))
(define put (eval-table 'insert-proc!))

(define (eval-quoted exp env)
(text-of-quotation exp))

(define (eval-set exp env)
(eval-assignment exp env))
(define (eval-define exp env)
(eval-definition exp env))
(define (eval-if. exp env)
(eval-if exp env))
(define (eval-lambda exp env)
(make-procedure (lambda-parameters exp)
(lambda-body exp)
env))
(define (eval-begin exp env)
(eval-sequence (begin-actions exp) env))
(define (eval-cond exp env)
(eval (cond->if exp) env))
(put 'quote eval-quoted)
(put 'set eval-set)
(put 'define eval-definition)
(put 'if eval-if.)
(put 'lambda eval-lambda)
(put 'begin eval-begin)
(put 'cond eval-cond)


(define (eval exp env)
(cond ((self-evaluating? exp) exp)
((variable? exp) (lookup-variable-value exp env))
((get (car exp))
((get (car exp)) exp env))
((application? exp)
(apply (eval (operator exp) env)
(list-of-values (operands exp) evn)))
(else
(error "Unknown expression type -- EVAL" exp))))


연습문제 4.2

a. 프로시저 적용이 우선되게될 때 (define x 3)를 예로 들어 보자.
이 경우 eval은 (define x 3)를 define 정의 식이 아니라, 일반 프로시저로 인식하게 된다.
따라서 define이라는 프로시저에 (x 3) 을 넣어 해당하는 결과를 수행하도록 식을 평가하게된다. 따라서, application이 무리하게 먼저 실행되면 심각한 문제가 발생하게된다.

b. 굳이 application을 call을 사용해서 수행하고 싶다면 다음과 같이 변경한다.
<blockquote>
(define (application? exp) (tagged-list? exp 'call))
(define (operator exp) (cadr exp))
(define (operands exp) (cddr exp))</blockquote>


연습문제 4.1


(define (list-of-values exps env)
(if (no-operands? exps)
'()
(let ((left-values (eval (first-operands exps))))
(let ((right-values (list-of-values (rest-operands exps))))
(cons left-values right-values)))))


오른쪽부터 셈하도록 하려면 left-values와 right-values의 위치를 바꿔주면 된다.

2008. 8. 27.

연습문제 3.79


<blockquote>(define (solve-2nd f y0 dt)
(define y (integral (delay dy) y0 dt))
(define dy (integral (delay ddy) y0 dt))
(define ddy (stream-map f dy y))
y)</blockquote>


연습문제 3.78


(define (solve-2nd a b y0 dt0 dt)
(define y (integral (delay dy) y0 dt))
(define dy (integral (delay ddy) y0 dt))
(define ddy (add-stream (scale-stream dy a)
(scale-stream y b)))
y)


연습문제 3.77

<blockquote>
(define (integral delayed-integrand initial-value dt)
(cons-stream initial-value
(let ((integrand (force delayed-integrand)))
(if (stream-null? integrand)
the-empty-stream
(integral (delay (stream-cdr integrand))
(+ (* dt (stream-car integrand))
initial-value)
dt)))))</blockquote>


2008. 8. 26.

연습문제 3.34

(set-value! B 100 'user)

Probe: B = 100
done

과 같은 결과가 나온다. 즉 A의 값이 구성되지 않는다.
이는 종단점이 3개가 있지만 그 중 하나만 구성되는 것을 볼 수 있다.
multiplier에서 B값은 product에 대응한다. m1, m2에 해당하는 값은 세팅되어있지않으므로 해당하는 값을 구할 수가 없다.

연습문제 3.66

pair의 선두에는 S, T의 선두값이 오고 interleave값이 온 후 다시 재귀적으로 돈다.

몇차례의 step을 밟아보면..
(1 1)
(1 2)
(2 2)
(1 3)
(2 3)
(1 4)
(3 3)
(1 5)
(2 4)
(1 6)
매 짝수열마다 (1, n)항이 오는 것을 알 수 있다.
따라서 (1, n) 이전의 모든 pair의 수는 2(n-1)개가 된다.
 이후는 생략..

연습문제 3.65

PI와 비슷하게 sum 만을 뽑고, 그리고 scale을 계산하도록 하자.

(define (ln2-summands n)
  (cons-stream (/ 1.0 n)
                     (stream-map - (ln2-summands (+ n 1))))

(define ln2-stream
  (scale-stream (partial-sum (ln2-summands 1)) 4)


연습문제 3.64

해당 스트림에서 다음번 얻어지는 값은 cdr중 car한 값 즉, cadr 값이다.
따라서 우선 스트림에서 cadr을 수행하는 stream-cadr을 만든다.

(define (stream-cadr s)
  (stream-car (stream-cdr s)))


이제 stream-limit을 정의한다.

(define (stream-limit s tol)
  (if ( < (abs (- (stream-car s) (stream-cadr s)) tol)
    (stream-card s)
    (stream-limit (stream-cdr tol)))


연습문제 3.63

memo-func 내에서 (proc)를 호출하는 일이 있는데, sqrt-stream을 바로 쓰면, 이 때 해당 proc가 바로 호출되므로 불필요한 계산이 발생한다.

2008. 8. 25.

연습문제 3.58

해당하는 연산은 주어진 수num을 den으로 나눈 값으로, radix 진수로 나타낸다.

상세한 계산 결과는 생략한다.

연습문제 3.57

이전에 memo-func을 이용한다면 각 fibs가 수행될때마다 해당하는 값이 기입되어 나가므로 덧셈은 n-1번만 수행된다.

memo-func을 사용하지않는다면 fibs는 이전에 tree를 만든 형식처럼 지수함수적으로 증가하게 된다.

연습문제 3.56

(define S
  (cons-stream 1
    (merge (scale-stream integers 2)
                (merge (scale-stream integers 3)
                           (scale-stream integers 5)))))

연습문제 3.55

(define (partial-sums s)
  (cons-stream (stream-car s)
                        (add-streams (stream-cdr s) (partial-sums s))))



연습문제 3.54

(define (mul-streams m1 m2)
  (stream-map * m1 m2))

(define factorials (cons-stream 1 (mul-streams factorials integers)))


연습문제 3.53

1, 2, 4, 8, 16 식으로 2^n으로 늘어나는 스트림이다.