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으로 늘어나는 스트림이다.

2008. 8. 23.

연습문제 3.50

(define (stream-map proc . argstreams)
  (if (stream-null? (car argstreams))
      the-empty-stream
      (cons-stream
       (apply proc (map stream-car argstreams))
       (apply stream-map
              (cons proc (map stream-cdr argstreams))))))


2008. 8. 21.

연습문제 3.48

<blockquote>(define (make-account number balance)
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))
(define (deposit amount)
(set! balance (+ balance amount))
balance)
(let ((balance-serializer (make-serializer)))
(define (dispatch m)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
((eq? m 'number) number)
((eq? m 'balance) balance)
((eq? m 'serializer) balance-serializer)
(else (error "Unknown request -- MAKE-ACCOUNT"
m))))
dispatch))

(define (serialized-exchange account1 account2)
(let ((serializer1 (account1 'serializer))
(serializer2 (account2 'serializer)))
(if (< (account1 'number) (account2 'number))
((serializer2 (serializer1 exchange))
account1 account2)
((serializer1 (serializer2 exchange))</blockquote>
account1 account2))))


연습문제 3.47

a.
<blockquote>(define (make-semaphore-mtx maximal)
(let ((count maximal)
(mutex (make-mutex)))
(define (the-sema m)
(cond ((eq? m 'release)
(mutex 'acquire)
(unless (= count maximal)
(set! count (+ 1 count)))
(mutex 'release))
((eq? m 'acquire)
(mutex 'acquire)
(cond
((> count 0)
(set! count (- count 1))
(mutex 'release))
(else
(mutex 'release)
(the-sema 'acquire))))
(else
(error "Unknown request -- " m))))
the-sema))</blockquote>
b.
<blockquote>(define (loop-test-and-set! cell)
(if (test-and-set! cell)
(loop-test-and-set! cell)
'()))

(define (make-semaphore-ts maximal)
(let ((count maximal)
(guard (cons #f '())))
(define (the-sema m)
(cond ((eq? m 'release)
(loop-test-and-set! guard)
(unless (= count maximal)
(set! count (+ 1 count)))
(clear! guard))
((eq? m 'acquire)
(cond
(loop-test-and-set! guard)
((> count 0)
(set! count (- count 1))
(clear! guard))
(else
(clear! guard)
(the-sema 'acquire))))
(else
(error "Unknown request -- " m))))
the-sema))
</blockquote>


연습문제 3.46

어떤 프로시저 p1이 test-and-cset!에서 (car cell)을 통과했다고 가정하고 이때 p2가 mutex에 접근해서 수행한다면 아직 cell 값이 변경되지 않은 상황에서 p2가 실행될 가능성이 있다
따라서 이 경우 p1, p2가 모두 실행될 수 있다.

연습문제 3.44

금액의 전송에서 인출과 송금은 각기 차례열로 지어져있으므로 오류에 대해 안전하다.
따라서 Ben의 생각이 옳다고 본다.
다 만 이전 문제에서는 두 계좌의 차이를 구하는 작업이 중요했다면, 이번 문제에서는 그런 것 없이 실제로 인출이 가능한지 여부가 더 중요하다. 다만 from-account에 남은 돈이 항상 amount만큼 된다고 가정했기 때문에, 문제가 없다고 볼 수 있다.

연습문제 3.43

세 계정을 각각 a, b, c라고 하고 계정의 잔액을 맞바꾸는 연산을 e-ab, e-bc, e-ca라고 하자.
이 경우 프로세스가 차례대로만 돌아준다면 다음과 같은 순서가 유지된다.

phase 1 e-ab: 20 10 30
phase 2 e-bc: 20 30 10
phase 3 e-ca: 10 30 20
phase 4 e-ab: 30 10 20
phase 5 e-bc: 30 20 10
phase 6 e-ca: 10 20 30

즉 6번의 수행후에는 다시 원래대로 반복된다.

그렇지만 줄세워지지않은 exchange로 변동되는 경우
phase 1의 계산중이라면 아직 10 20 30 순으로 저장되어 있으나 a, b의 차액 -10은 계산이 되어있다고 하고, 바로 phase-3가 끝났다고 하면 금액은 30 20 10 이 된다.
이제 phase 1이 마무리되면 a에서 -10을 빼고 b에 -10을 더해야하므로 40 10 10 이라는 결과가 나온다.
따라서 계정 금액이 무너지게 된다.

다만 계정에서 더하고 뺀 값의 총합은 0이기 때문에 전체 금액의 변화는 없게된다.

연습문제 3.42

병행처리에서 줄세워지는 것은 생성시의 문제가 아니라 실제로 해당하는 프로시저가 parrerel-excute를 통해 수행될 때 결정된다. 따라서 이런 변경이 프로그램 수행에 큰 변경이 일어나지는 않을 것으로 본다.

연습문제 3.41

실제 balance의 값을 변경하는 메서드 withdraw와 deposit이 모두 줄세워졌기때문에 실제 어플리케이션에서 balance를 출력하는 구문이 줄세워지는 것은 별 문제가 되지 않는다.

연습문제 3.40

줄세우지 않은 경우는 여러가지가 가능하다.

P1을 모두 계산하고 P2를 계산하는 경우 : 1000000
P2를 계산하고 P1을 계산하는 경우 : 1000000
P1의 계산이 끝난후 P2를 계산하고 P2의 덮어쓰기 이후 P1의 덮어쓰기가 일어나는 경우 100
P1의 계산이 끝난후 P2를 계산하고 P1의 덮어쓰기 이후 P2의 덮어쓰기가 일어나는 경우 1000
P2의 계산이 끝난후 P1을 계산하고 P2의 덮어쓰기 이후 P1의 덮어쓰기가 일어나는 경우 100
P2의 계산이 끝난후 P1을 계산하고 P1의 덮어쓰기 이후 P2의 덮어쓰기가 일어나는 경우 1000

줄세운 겨우에는 P1의 끝나고 P2가 수행되므로 1000000 이 나온다.

연습문제 3.39

순차대로 실행되는 해당 프로시저중 serializer가 된 함수는 x를 하나 늘리는 것과 x를 거듭제곱하는 두개의 프로시저가 있다.
문제는 이렇게 차례지은 프로시저중 하나만이 제대로 등록된다는 점이다.
따라서 해당하는 값은 크게

거듭제곱 -> x 저장 -> 하나 늘리기 : 101
거듭제곱 -> 하나 늘리기 -> 거듭제곱 결과 저장 : 100
하나늘리기 -> 거듭제곱 -> 결과 저장 : 121

이 세가지가 모두 가능하게 된다.

연습문제 3.38

a.
Peter, Paul, Mary -> 45
Peter, Mary, Paul -> 35
Mary, Peter, Paul -> 40
Mary, Paul, Peter -> 40
Paul, Peter, Mary -> 45
Paul, Mary, Peter -> 50

b. Peter가 실행해서 일단 balance를 110으로 계산한다. 다음에 Pault은 이전 balance 100을 가지고 해당 값을 80으로 맞춘다.  paul의 프로세스가 balance를 110으로 맞춘다. 마지막으로 mary가 값을 55로 맞춘다. 이런 시나리오가 가능하다.

2008. 8. 20.

연습문제 3.37

(define (c+ x y)
  (let ((z (make-connector)))
    (adder x y z)
    z))

(define (c* x y)
  (let ((z (make-connector)))
    (multiplier x y z))
  z)

(define (c/ x y)
  (let ((z (make-connector)))
    (multiplier x z y))
  z)

(define (cv n)
  (let ((a (make-connector)))
    (constant n a)
    a))



연습문제 3.35

(define (squarer a b)
(define (process-new-value)
(if (has-value? b)
(if (< (get-value b ) 0)
(error "square less than 0 -- SQUARER" (get-value b))
(set-value! a (sqrt (get-value b)) me))
(if (has-value? a)
(set-value! b (square (get-value a)) me) )))
(define (process-forget-value)
(forget-value! a me)
(forget-value! b me))
(define (me request)
(cond ((eq? request 'I-have-a-value)
(process-new-value))
((eq? request 'I-lost-my-value)
(process-forget-value))
(else
(error "Unknown request -- SQUARER" request))))
(connect a me)
(connect b me)
me)

연습문제 3.34

(set-value! B 100 'user)

Probe: B = 100
done

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

연습문제 3.33

(define (averager a b c)
(let ((u (make-connector))
(v (make-connector)))
(adder a b u)
(multiplier c v u)
(constant 2 v)
'ok))

2008. 8. 14.

연습문제 3.32

회로에서 개별 회로는 이전에 일어난 결과를 토대로 동작하게된다. 조각 시간에 들어있는 프로시저는 회로의 구성에 따라 수행순서가 들어가기때문에 이런 차례는 반드시 따라야 한다.

연습문제 3.31

프로시저를 곧바로 호출하면서 wire에 연산이 추가될 때 즉시적인 결과가 발생한다. 즉 after-delay가 호출되면서 자연스럽게 agenda에 회로데이터가 적재된다.
만약 프로시저를 곧바로 호출하지않는다면, 실제 agenda에 적용시켜주기위해서는 논리적으로 회로의 순서에 맞게끔 해당 회로를 다시 실행시켜주어야하는 작업이 있어야한다.

연습문제 3.30

(define (ripple-carry-adder lista listb lists c)
  (let ((lc '()))
    (define (inner-ripple la lb ls ck)
      (if (null? la)
          'ok
          (begin
            (let ((cout (make-wire)))
              (full-adder (car la) (car lb) ck (car ls) cout)
              (append cout lc)                   
              (inner-ripple (cdr la) (cdr lb) (cdr ls)) cout))))
    (inner-ripple lista listb lists c)))

뒤쳐지는 시간을 논리곱, 논리합, 인버터 시간으로 표현하면..
inner-ripple은 모두 n번 호출되므로 full-adder 역시 n번 호출된다.
full-adder는 2개의 half-adder와 하나의 논리합으로 구성되어있다.
half-adder는 두개의 논리곱, 하나의 논리합, 하나의 인버터로 구성되어 있다.

따라서 full-adder는 네개의 논리곱, 세개의 논리합, 하나의 인버터 만큼 시간지연이 발생한다.
그러므로 ripple-carry-adder는 총 4n 논리곱 + 3n 논리합 + n인버터 지연시간이 필요하게된다.

연습문제 3.29

드 모르강의 법칙에 따라 P v Q = (~ (~ P ^ ~Q))와 같으므로..
(define (or-gate a1 a2 output)
  (let ((na1 (make-wire))
        (na2 (make-wire))
        (nand (make-wire)))
    (inverter a1 na1)
    (inverter a2 na2)
    (and-gate na1 na2 nand)
    (inverter nand output)))

와 같이 정의할 수 있다.
이때 발생하는 delay는 and-gete-delay + (3 * inverter-delay) 와 같다.

연습문제 3.28

(define (or-gate a1 a2 output)
  (define (or-action-procedure)
    (let ((new-value (logical-or (get-signal a1) (get-signal a2))))
      (after-delay or-gate-delay
                   (lambda ()
                     set-signal! output new-value))))
  (add-action! a2 or-action-procedure)
  (add-action! a1 or-action-procedure)
  'ok)


2008. 8. 13.

연습문제 3.27

memorize가 호출되면 새로운 환경이 생성된다.
이 환경에서 table이 구성되며, 테이블에 넘겨진 인자 n과 다른 값이 들어오면 기존의 factorial lambda연산을 수행하고 그렇지 않은 경우에는 테이블을 lookup 하게 된다.

memo- fib를 (memorize fib)로 변경한 경우 fib자체가 memo-fib에 의해 정의되지 않기때문에 이전에 테이블에 저장되지 않은 값의 경우 이전처럼 지수비례로 자라난다. 물론 이전에 계산한 데이터의 경우에는 테이블에서 lookup하여 찾을 수 있다.

2008. 8. 12.

연습문제 3.24

(define false #f)
(define (make-table same-proc)
  (let ((local-table (list '*table*)))
    (define (assoc key records)
      (cond ((null? records) false)
            ((same-proc key (caar records)) (car records))
            (else (assoc key (cdr records)))))
    (define (lookup key-1 key-2)
      (let ((subtable (assoc key-1 (cdr local-table))))
        (if subtable
            (let ((record (assoc key-2 (cdr subtable))))
              (if record
                  (cdr record)
                  false)))))
    (define (insert! key-1 key-2 value)
      (let ((subtable (assoc key-1 (cdr local-table))))
        (if subtable
            (let ((record (assoc key-2 (cdr subtable))))
              (if record
                  (set-cdr! record value)
                  (set-cdr! subtable
                            (cons (cons key-2 value)
                                  (cdr subtable)))))
            (set-cdr! local-table
                      (cons (list key-1
                                  (cons key-2 value))
                            (cdr local-table)))))
      'ok)
    (define (dispatch m)
      (cond ((eq? m 'lookup-proc) lookup)
            ((eq? m 'insert-proc!) insert!)
            (else (error "Unknown operator -- TABLE" m))))
    dispatch))


연습문제 3.23

Deque 문제는 양방향 링크 리스트로 푼다.

(define (make-deque) (cons '() '()))

(define (front-ptr deque) (car deque))
(define (rear-ptr deque) (cdr deque))
(define (set-front-ptr! deque item) (set-car! deque item))
(define (set-rear-ptr! deque item) (set-cdr! deque item))

(define (empty-deque? deque) (null? (front-ptr deque)))
(define (front-deque deque)
  (if (empty-deque? deque)
      (error "Empty deque")
      (cadr (front-ptr deque))))
(define (rear-deque deque)
  (if (empty-deque? deque)
      (error "Empty deque")
      (cadr (rear-ptr deque))))

(define (front-insert-deque! deque item)
  (let ((ele (list '() item '())))
    (cond ((empty-deque? deque)
           (begin
             (set-front-ptr! deque ele)
             (set-rear-ptr! deque ele)))
          (else
           (begin
             (set-car! (cddr ele) (front-ptr deque))
             (set-car! (front-ptr deque) ele)
             (set-front-ptr! deque ele))))))
(define (rear-insert-deque! deque item)
  (let ((ele (list '() item '())))
    (cond ((empty-deque? deque)
           (begin
             (set-front-ptr! deque ele)
             (set-rear-ptr! deque ele)))
          (else
           (begin
             (set-car! ele (rear-ptr deque))
             (set-car! (cddr (rear-ptr deque)) ele)
             (set-rear-ptr! deque ele))))))

(define (front-delete-deque! deque)
    (cond ((empty-deque? deque)
           (error "Empty queue " deque))
          (else
           (begin
             (set-front-ptr! deque (caddr (front-ptr deque)))
             (set-car! (car (front-ptr deque)) '())))))

(define (rear-delete-deque! deque)
    (cond ((empty-deque? deque)
           (error "Empty queue " deque))
          (else
           (begin
             (set-rear-ptr! deque (car (rear-ptr deque)))
             (set-car! (cddr (rear-ptr deque)) '())))))


(define (print-deque deque)
  (define (print-dl double-list)
    (if (null? double-list)
        (display "")
        (begin
          (display (cadr double-list))
          (print-dl (caddr double-list)))))
  (cond ((empty-deque? deque) (display ""))
        (else
         (print-dl (front-ptr deque)))))


연습문제 3.22

(define (make-queue)
  (let ((front-ptr '())
        (rear-ptr '()))
    (define (set-front-ptr! item)
      (set! front-ptr item))
    (define (set-rear-ptr! item)
      (set! rear-ptr item))
    (define (empty-queue?)
      (null? front-ptr))
    (define (insert-queue! item)
      (let ((new-pair (cons item '())))
        (cond ((empty-queue?)
               (set-front-ptr! new-pair)
               (set-rear-ptr! new-pair))
              (else
               (set-cdr! rear-ptr new-pair)
               (set-rear-ptr! new-pair)))))
    (define (delete-queue!)
      (cond ((empty-queue?)
             (error "DELETE! called with an empty queue"))
            (else
             (set-front-ptr! (cdr front-ptr)))))
    (define (print-queue)
      (display front-ptr))
    (define (dispatch m)
      (cond ((eq? m 'insert-queue!) insert-queue!)
            ((eq? m 'empty-queue?) empty-queue?)
            ((eq? m 'print-queue) print-queue)
            ((eq? m 'delete-queue!) delete-queue!)
            (else
             (error "Unknown request -- MAKE-QUEUE" m))))
    dispatch))


연습문제 3.21

Ben은 queue가 리스트를 가르키는 pair임을 잊고 이다. queue는 car에는 리스트의 가장 앞을, cdr에는 리스트의 가장 뒤를 가르키고 있기때문에 실제 출력을 한다면 해당하는 리스트 전체와, 가장 뒤 요소를 동시에 출력하게 된다.

front-ptr 로 얻어진 리스트는 해당하는 queue 전체의 내용과 동일하므로 다음과 같이 print-queue를 만들 수 있다.

(define (print-queue queue)
  (cond ((empty-queue? queue) (display ""))
        (else
         (display (front-ptr queue)))))


2008. 8. 11.

연습문제 3.20

앞의 cons를 이용했다고 하면

z는 x가 가르키는 pair로 묶은 또다른 pair이다.

그러므로 z의 cdr은 x가 되고 그 x의 car을 변경했으므로 (car x)는 17이 된다.

연습문제 3.16

3이 나오는 경우

(define z (list 'a 'b 'c)

4가 나오는 경우

이 경우는 하나의 pair 가 추가되면 되므로..

(set-car! (cdr z) (cddr z))

라고 하면 된다.

7이 나오는 경우

이 경우는 z의 car이 그 cdr을 가르키게 하면된다.

(set-car! z (cdr z))

연습문제 3.14

mystery는 list의 값을 역으로 만드는 함수이다.

v -> (a)
w -> (d c b a)

가 된다.

연습문제 3.13

Z의 얼개는 다음과 같다..

  +------------------+
  |                       |
  v                      |
  * | * -> * | * -> * | *
  |          |          |
  v         v        v
  a         b        c


따라서 (last-pair z)는 무한 루프에 빠진다.

연습문제 3.12

append 연산을 끝마친 후 x의 cdr은

-> (b )

이고

append! 연산을 끝마친 후 x의 cdr은

-> (b c d)

이다.

연습문제 3.12

append 연산을 끝마친 후 x의 cdr은

-> (b )

이고

append! 연산을 끝마친 후 x의 cdr은

-> (b c d)

이다.

2008. 8. 7.

연습문제 3.8

(define f
  (let ((inner-v 1))
    (lambda (v)
      (begin
        (set! inner-v (* inner-v v))
        inner-v))))


연습문제 3.7

(define (make-joint account passwd newpasswd)
  (define (dispatch pass m)
    (if (?eq pass newpasswd)
        (account passwd m)
        (else (error "Bad passwd when joint"))))
  dispatch)


연습문제 3.6

(define (rand command)
(cond ((eq? command'generate) (random))
((eq? command 'reset)
(lambda (new)
(random-seed new)))
(else
(error "Bad command -- " command))))


연습문제 3.5

((define (monte-carlo trials experiment)
(define (iter trials-remaining trials-passed)
(cond ((= trials-remaining 0)
(/ trials-passed trials))
((experiment) (iter (- trials-remaining 1) (+ trials-passed 1)))
(else (iter (- trials-remaining 1) trials-passed))))
(iter trials 0))

(define (random-in-range low high)
(let ((range (- high low)))
(+ low (random range))))

(define (square-area x1 y1 x2 y2)
(let ((width (- x2 x1))
(height (- y2 y1)))
(* width height)))

(define (estimate-integral p x1 y1 x2 y2 trials)
(let ((test
(lambda ()
(p (random-in-range x1 x2)
(random-in-range y1 y2)))))
(* (square-area x1 y1 x2 y2)
(monte-carlo trials test))))

(define (square x) (* x x))

(define (P rx ry)
(<= (+ (square (- rx 5)) (square (- ry 7))) 9))

2008. 8. 6.

CLISP + SDL 연동

몇달간에 뻘짓을 거쳐서 성공했다.. 여기에 그 글을 올린다. -ㅇ-

준비물
  1. asdf
  2. cffi
  3. lispbuilder-sdl류..
여기에 그 찬란한 뻘짓을 올린다.

예전에 emacs + clisp + slime을 연동시켰다.

일단 홈디렉토리를 찾는다.. 내 경우는 D:\util\msys\home 이었다.
이것은 윈도에서 환경변수에 HOME을 등록시켜주면 된다.
해당하는 홈디렉토리에 .emacs를 만들고 거기에 다음과 같이 넣어주면 clisp+slime 연동은 끝!

;; Slime Module + CLISP
    (add-to-list 'load-path "d:/util/slime/")  ; your SLIME directory
    (setq inferior-lisp-program "d:/util/clisp/clisp.exe") ; your Lisp system
    (require 'slime)
    (slime-setup)
(add-hook 'lisp-mode-hook (lambda() (slime-mode t)))
(add-hook 'inferior-lisp-mode-hook (lambda () (inforior-slime-mode t)))
(autoload 'paredit-mode "paredit"
  "Minor mode for psedo-structurally editing Lisp code." t)
(add-hook 'lisp-mode-hook (lambda () (paredit-mode +1)))
필 요한 것은 사실 몇줄 안된다. 상단에 load-path에는 slime이 설치된 곳(slime은 cvs로 설치했다) 을 inferior-lisp-program에는 clisp.exe의 경로를 적어주면 끝이다. 이후 (require 'slime) (slime-setup)은 단순한 실행 셋업이다..

두번째로 clisp에서 asdf설정을 해주어야한다.

(load "d:/util/clisp/asdf/asdf.lisp")
(pushnew "d:/util/clisp/lib/" asdf:*central-registry* :test #'equal)
asdf는 어떻게 설치했느냐고? asdf는 cvs로 설치했다.
그 리고 asdf:*central-registry*를 설정했는데 이상하게 asdf.lisp과 같은 디렉에 있으면 뻑나길래 걍 다른 디렉토리 만들어 설치했다. 이 내용으로 HOME 디렉토리(D:\util\msys\home)에다가 .clisprc파일을 만들어 그 안에다 넣는다.

세번째 CFFI를 설치한다.

CFFI는 일단 최신 버전을 설치해주었다.
또한 여기에 의존이 걸린 Bebel, alexandria, trivial-features를 설치한다.

http://common-lisp.net/project/cffi/releases/cffi_latest.tar.gz
http://common-lisp.net/project/babel/releases/babel_latest.tar.gz
darcs get http://common-lisp.net/project/alexandria/darcs/alexandria
darcs get http://common-lisp.net/~loliveira/darcs/trivial-features
darcs도 깔아주었다. 이 놈은 CVS, SVN과 비슷한 놈인거 같은데.. 일단은 설치..

위에 4개의 모듈을 모두 d:/util/clisp/lib/ 에 풀어주었다.

네번째 lispbuilder-sdl을 설치한다.

일단 몰라서 lispbuilder-sdl관련 패키지는 모두 깔았다.

http://lispbuilder.sourceforge.net/ 에 가면 별에 별 패키지가 다 있다.
또 SDL을 설치한다. 혹시 SDL설치하기 짜증난다면 위에 사이트에서 windows binaries가 있다. 해당하는 패키지도 모두 받아서 설치하자.

마지막, 즐거운 시동

시 동에 앞서서.. 모든 모듈안에 들어있는 .asd 파일을 일단 단축 아이콘을 만들어 d:/util/clisp/lib/ 에 넣는다. 이름은 원래 파일명과 동일하게 모두 바꿔준다. 리눅스에서 ln을 통해서 링크 만들어준다고 하면 된다.

<span class="br0"></span><blockquote><span class="br0">(</span>asdf:<span class="me1">operate</span> 'asdf:<span class="me1">load</span>-op :<span class="me1">lispbuilder</span>-sdl<span class="br0">)</span></blockquote><span class="br0">

해서 정상적으로 컴파일이 되었다면

</span><span class="br0"></span><blockquote><span class="br0">(</span>asdf:<span class="me1">operate</span> 'asdf:<span class="me1">load</span>-op :<span class="me1">lispbuilder</span>-sdl-examples<span class="br0">)</span></blockquote><span class="br0">

으로 examples를 컴파일하고 실제 예제를 실행시키면 된다.

</span><span class="br0"></span><blockquote><span class="br0">(</span>sdl-examples:<span class="me1">bezier</span><span class="br0">)</span></blockquote><span class="br0">
이상으로 3개월에 걸친 뻘짓을 마친다.

주의해야할 점은..

</span>
  1. CFFI는 항상 최신버전을 사용하고..
  2. .ASD의 단축 아이콘을 asdf:*central-registry* 에 포함된 디렉토리에 넣어야한다.
<br /><br />는 점이다.<br />이거 몰라서 <span class="br0">뻘짓한거 생각하면 참 우울하다..</span>


연습문제 3.4

(define (make-account balance password)
  (let ((invalid-count 0))
    (define (withdraw amount)
      (if (>= balance amount)
          (begin (set! balance (- balance amount))
                 balance)
          "Insufficient funds"))
    (define (call-the-cops msg)
      (error "Invalid password" msg))
    (define (deposit amount)
      (set! balance (+ balance amount))
      balance)
    (define (dispatch pass m)
      (cond ((eq? password pass)
             (cond ((eq? m 'withdraw) withdraw)
                   ((eq? m 'deposit) deposit)
                   (else (error "Unknown request -- MAKE-ACCOUNT" m))))
            (else
             (begin
               (set! invalid-count(+ invalid-count 1))
               (if (> invalid-count 7)
                   (call-the-cops "help")
                   (lambda (x) "Bad Password"))))))
    dispatch))

연습문제 3.3

(define (make-account balance password)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds"))

  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)

  (define (dispatch pass m)
    (cond ((eq? password pass)
           (cond ((eq? m 'withdraw) withdraw)
              ((eq? m 'deposit) deposit)
              (else (error "Unknown request -- MAKE-ACCOUNT" m))))
          (else (error "Incorect password" pass))))

  dispatch)

연습문제 3.2

(define (make-monitored f)
  (let ((calls 0))
    (define (mf m)
      (cond ((eq? m 'how-many-calls) calls)
            ((number? m)
             (begin (set! calls (+ calls 1))
                    (f m)))))
    mf))

연습문제 3.2

(define (make-monitored f)
(let ((calls 0))
(define (mf m)
(cond ((eq? m 'how-many-calls) calls)
((number? m)
(begin (set! calls (+ calls 1))
(f m)))))
mf))

연습문제 3.1

(define (make-accumulator n)
  (lambda (a)
    (begin
      (set! n (+ n a))
      n)))