Books by Example/SICP2007.12.16 03:55

연습문제 1.21은 너무 쉬우므로 생략합니다. 1.22는 이미 있는 소스 코드를 가지고 search-for-primes라는 프로시저를 작성하는 것입니다. 기존의 프로시저를 아무 수정없이 사용할 수는 없는데, 그것은 start-prime-test가 검사 대상 수 n이 prime이 아닐 때 false를 반환하도록 구현되어 있지 않기 때문입니다. 그래서 아래의 소스 코드 붉은 색으로 표기된 부분에 false를 반환하는 코드를 넣었습니다. (저것말고 더 쉬운 방법이 있을텐데 지금으로선 잘 모르겠네요. ㅋ)

아 그리고, PLT-scheme은 SICP 책에 나오는 runtime이라는 함수를 제공하지 않습니다. 대신 current-seconds나 current-milliseconds같은 함수들을 제공합니다. (language를 PLT 아래에 있는 것 중 하나로 선택하면 사용할 수 있습니다.) 그래서 그 함수들을 사용하도록 코드를 고쳤습니다. (아래에 녹색 표시된 부분)

(define (smallest-divisor n)
  (find-divisor n 2))

(define (find-divisor n test-divisor)
  (cond ((> (square test-divisor) n) n)
        ((divides? test-divisor n) test-divisor)
        (else (find-divisor n (+ test-divisor 1)))))

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

(define (divides? a b)
  (= (remainder b a) 0))

(define (prime? n) (= (smallest-divisor n) n))

(define (timed-prime-test n)
  (start-prime-test n (current-milliseconds)))

(define (start-prime-test n start-time)
  (if (prime? n)
      (report-prime n (- (current-milliseconds) start-time))
      (= 1 0)))

(define (report-prime n elapsed-time)
  (newline)
  (display n)
  (display " is prime and ")
  (display elapsed-time)
  (display " milli-seconds have passed"))

(define (search-for-primes start-from count)
  (if (> count 0)
      (if (even? start-from)
          (search-for-primes (+ start-from 1) count)
          (if (timed-prime-test start-from)
              (search-for-primes (+ start-from 2) (- count 1))
              (search-for-primes (+ start-from 2) count)))))

(display (sqrt 10))
(search-for-primes 1000000000 3)
(newline)
(search-for-primes 10000000000 3)
(newline)
(search-for-primes 100000000000 3)
(newline)
(search-for-primes 1000000000000 3)

맨 마지막의 8줄은 실행 결과를 확인하기 위한 부분입니다. sqrt 10이 대략 3입니다. search-for-primes의 실행 결과는 탐색이 시작되는 수의 자릿수가 10이 증가할 때 마다 대략 3배씩 늘어납니다. (따라서, 책에서 '정말 그러한가?'하고 묻는 부분에 대한 답은 'yes'라고 할 수 있겠습니다.)

아이가 아파서 늦게까지 잠을 잘 수가 없었는데, 이제 열도 떨어지고 했으니 그만 자야겠습니다.


신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. runtime이 안되어 고생하였는데 먼저 해결책을 알려주셔서 고맙습니다.^^ㅜㅜ

    2008.01.17 15:20 신고 [ ADDR : EDIT/ DEL : REPLY ]

Books by Example/SICP2007.11.17 17:50

본문에 나오는 이야기입니다만, T(a,b): (a <- a + b, b <- a)라고 하고, T 규칙을 순차적으로 n번 적용한 것을 T^n이라고 하면, T^n(1,0)은 n번째 피보나치 수열이죠.

그런데 사실 이 규칙 T는

  T_{p,q}(a,b): (a <- bq + aq + ap, b <- bp + aq)

의 특별한 케이스(p=0, q=1)입니다.

여기까지를 알고 있을때, 규칙 T_{p,q}를 연속적으로 두 번 적용해 보면(T_{p,q}^2) 어떻게 되나요?

a <- (bp + aq)q + (bq+aq+ap)q + (bq+aq+ap)p
       = b(2pq+q^2) + a(2pq+q^2) + a(p^2+q^2)
b <- (bp+aq)p + (bq+aq+ap)q
       = b(p^2 + q^2) + a(2pq+q^2)

결국, p^2+q^2 = p', 2pq+q^2 = q'로 놓게되면

  a <- bq' + aq' + ap', b <- bp' + aq'

이 됩니다.

그렇다면 피보나치 수열을 계산하는데 필요한 인자를 a, b, p, q의 네 가지로 보았을 때, 이터레이션의 수를 반으로 줄이고 싶으면 그럴 때 마다 a, b, p, q를 a, b, p^2+q^2, 2pq+q^2로 바꾸면 되겠군요. 그렇게 할 수 없을 때에는 a, b, p, q를 bq+aq+ap, bp+aq, p, q로 바꾸면 되고요.

맨 마지막에는 이렇게 해서 만들어진 최종 4-tuple을 다시 (a, b, p, q)라고 했을 때 b를 반환하도록 하면 되겠습니다.

그렇다면 결국 책에 나온 Scheme 문제는 다음과 같이 채우면 되겠군요.

(define (fib n)
  (fib-iter 1 0 0 1 n))

(define (fib-iter a b p q count)
  (cond ((= count 0) b)
           ((even? count) (fib-iter a b (+ (* p p) (* q q)) (+ (* 2 p q) (* q q)) (/ count 2)))
           (else (fib-iter (+ (* b q) (* a q) (* a p)) (+ (* b p) (* a q)) p q (- count 1)))))

이 문제는 Scheme 식으로 생각하는 문제라기 보다는 수학 문제처럼 느껴진다는...


신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 전 피보나치 수열을 로그 차수가 나오는 알고리즘이 있다는 점이 무척 신기했습니다.^^

    2008.01.14 11:31 신고 [ ADDR : EDIT/ DEL : REPLY ]

Books by Example/SICP2007.11.15 22:27
1.16번

연습문제 1.16은 b를 n번 곱하는 문제의 복잡도를 어떻게 n에서 log n 으로 (밑수는 2)로 낮출 수 있느냐 하는 문제입니다. b * b * b * b * ... 이렇게 하는 대신 b를 계속해서 제곱해 나가다가 (b --> b^2 --> b^4 --> ... ) 마지막에 n이 홀수냐 짝수냐에 따라서 그 결과에 b를 한 번 더 곱해주거나 아니면 그냥 놔두거나 하면 되겠죠.

굉장히 간단한 아이디어입니다만, 의외로 실무에서 프로그래밍을 하다 보면 이렇게 간단한 부분도 놓치게 되는 일이 많은 것 같습니다.

비슷한 종류의 사례로 strcat에 관한 것도 있는데, 이에 대해서는 "조엘 온 소프트웨어"라는 책에 보면 나옵니다. strcat이 보통 '널 문자'를 찾기 위해 포인터를 문자열 앞에서 뒤 방향으로 계속 검색해 나가는데, 그런 이유로 strcat을 여러번 적용하면 문자열을 여러 개 합칠 경우 그 계산 복잡도가 n^n으로 바뀌고 만다, 뭐 그런 이야기였습니다.

아무튼 이 문제의 Scheme 식 해답은 다음과 같습니다.

(define (fast-expt-iter b n)
  (define (fast-expt-iter-part b m c)
    (cond ((= c 0) m)
          ((even? c) (fast-expt-iter-part (* b b) m (/ c 2)))
          (else (fast-expt-iter-part b (* b m) (- c 1)))))


  (fast-expt-iter-part b 1 n))

(fast-expt-iter 2 32)

"되도는 알고리즘보다 반복하는 알고리즘을 짜는 것이 더 어렵다"고 해서 (사실 그렇습니다) 문제 풀기전에 좀 겁먹었습니다만, 문제 자체가 쉬워서 크게 어려울 것은 없었습니다.

1.17번, 1.18번

그러면 a * b를 그런 식으로 계산할 수도 있겠군요. a * b를 덧셈만으로 구현한다고 하면 a를 b 번 더해나가야 되겠습니다만, a를 2a, 4a, 이런 식으로 계속 두 배 해 나가는 식으로 하면 더 빨리 돌도록 구현할 수 있겠습니다. 원래는 17번은 재귀 프로세스, 18번은 반복 프로세스로 구현하는 것인데, 재귀 프로세스로 구현하는 것은 반복 프로세스로 구현하는 것에 비해 쉬으므로, 반복 프로세스로 구현하는 경우만 보였습니다.

(define (double x) (* 2 x))

(define (halve x) (/ x 2))

(define (mul a b)
  (define (f adder result count)
    (cond ((= count 0) result)
          ((even? count) (f (double adder) result (halve count)))
          (else (f adder (+ result adder) (- count 1)))))
  (f a 0 b))

(mul 3 7)

신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

Books by Example/SICP2007.11.10 16:11

파스칼의 세모꼴(Pascal's Triangle) 문제는 널리 잘 알려진 문제입니다. 하지만 안타깝게도 이 책을 읽기 전에 저는 이 문제를 함수형 언어에서는 풀어본 적이 없습니다. 파스칼의 세모꼴 모양은 흔히 알려져 있는 대로, 다음과 같습니다.

http://www.mathsisfun.com/pascals-triangle.html

출처: http://www.mathsisfun.com/pascals-triangle.html


이 문제를 저는 이렇게 풀기로 했습니다. 우선 위에서 부터 아래쪽으로, 1부터 증가하는 번호를 매깁니다. 이것을 x라고 했습니다. 그리고 왼쪽에서 오른쪽으로 역시 1부터 증가하는 번호를 매깁니다. 이것을 y라고 합니다. 그렇다면 x와 y의 값에 따라서, 모든 수는 (x, y)의 유일한 좌표 값을 가집니다. 이 x, y 사이의 관계를 알 수 있으면 어떤 좌표에 있는 값이 무엇인지 알 수 있습니다.

(define (f x y)
  (if (or (= y 1) (= x y)) 1
      (+ (f (- x 1) (- y 1)) (f (- x 1) y))))


그 값을 알아내는 공식은 위와 같습니다. 이 공식을 만든 다음에, 이 공식을 사용해서 파스칼 삼각형을 화면에 출력하도록 했습니다. 안타깝게도 출력에 관한 사항을 어떻게 처리할 지는 그다지 배운 바가 없어서, 대충 출력하도록 만들었습니다. 적당히 잘 뜯어고치면, 이것보다는 더 나은 출력을 만들 수 있을 거라 믿습니다.

(define (pascal n)
  (define (pascal-iter x y)
    (cond ((and (= x n) (= y (+ n 1))) (display ""))
          ((= y (+ x 1)) (display "\n") (pascal-iter (+ x 1) 1))
          (else (display (f x y)) (display " ") (pascal-iter x (+ y 1)))))
  (pascal-iter 1 1))


이 코드를 다음과 같이 하여 실행합니다.

(pascal 5)

그러면 아래의 삼각형을 얻습니다. (5 보다 큰 수를 입력하면 출력이 영 볼썽 사납습니다 ㅋㅋ)

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1


그런데 문제를 풀고보니 화면 출력에 대한 내용까지를 풀 필요는 없고, 각 좌표의 수가 무엇인지를 알수만 있으면 되는 것 같습니다. (괜히 삽질했구나 하는 생각이 듭니다 -_-;;)

화면 출력에 관한 코드를 만들 때 곤란했던 부분은, 흔히 C++에서는 다음과 같이 표현되는 루프를 어떻게 만들 것이냐 하는 점이었습니다.

for ( int i = 1; i <= n; ++i ) {
    for ( int j = 1; j <= n; ++j ) {
        ...
    }
}


뭐 보시다시피 대충 해결했습니다. ^O^;;

신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. estel

    정보 감사합니다!

    2016.01.21 19:53 신고 [ ADDR : EDIT/ DEL : REPLY ]

Books by Example/SICP2007.11.10 09:50

이 문제는 되도는 프로시저를 사용해 되도는 프로세스와 반복 프로세스를 구현해 보는 문제입니다. 되도는 프로세스는 흔히 "재귀적 프로세스"라고 부르는 것이고, 반복 프로세스는 "iterative process"입니다. (프로시저와 프로세스는 다른 개념인데, 프로시저는 코드라고 생각하면 되고, 프로세스는 그 코드에 의해 만들어지는 실행 궤적이라고 생각하면 됩니다. 따라서 프로시저는 재귀적으로 구현되더라도, 그 실행 궤적 자체는 반복적이 되는 일이 Scheme같은 언어에서는 발생할 수 있습니다. C에서라면 좀 곤란하지만요.)

C와 같은 언어에서 전자는 흔히 '함수의 재귀적 호출'에 의해 구현되고 반복 프로세스는 for나 while과 같은 별도의 문법에 의해 구현됩니다만, lisp는 for와 같은 문법을 지원하지 않기 때문에 재귀적 프로세스나 반복 프로세스나 전부 재귀적인 프로시저에 의해 구현해야 합니다. 처음에는 이것이 이해가 잘 되지 않을 수 있습니다. 책에서는 재귀적 프로세스와 반복 프로세스의 차이를 다음과 같이 언급하고 있습니다.

반복하는 프로세스에서는 프로그램 변수가 프로세스 단계마다 어떤 상태에 있는지 정확하게 나타내기 때문에, 계산을 잠시 멈추더라도 각각의 변수의 값만 알면 실행기가 곧바로 계산을 이어갈 수 있다. 하지만 되도는 프로세스는 그렇지 않다. 프로세스 안에 상태변수도 없을 뿐더러, 뒤로 미뤄 둔 연산의 끈을 이어가면서 '어디까지 계산했는지' 알아내려면, 실행기 속에 숨은 정보가 더 있어야 한다. 끈이 길 수록 그런 정보는 더 많아진다.



1.11번 문제는 함수 f(n) = (n-1) + 2f(n-2) + 3f(n-3) (n < 3일때는 f(n) = n)을 재귀적 프로세스와 반복 프로세스 두 가지 다른 버전으로 구현해 보는 것입니다. 통상 재귀적 프로세스는 하향적으로 문제 풀이가 전개되는 반면, 반복 프로세스는 상향적으로 문제 풀이가 전개됩니다. 전자는 좀 연역적인 성격이 있고, 후자는 좀 귀납적인 성격이 있다, 이렇게도 볼 수 있겠습니다. 그 점을 염두에 두면 문제풀이가 쉬워지는 것 같습니다.

답은 아래에 있습니다.

(define (func n)
  (if (< n 3) n
      (+ (- n 1) (* 2 (func (- n 2))) (* 3 (func (- n 3))))))

(define (func-iter n)
  (define (func-iter-part a b c count)
    (if (= count n) (+ (- count 1) (* 2 b) (* 3 c))
        (func-iter-part (+ (- count 1) (* 2 b) (* 3 c)) a b (+ count 1))))
  (if (< n 3) n
      (func-iter-part 2 1 0 3)))

(func 8)

(func-iter 8)

이렇게 할 수도 있습니다.

(define (func-iter n)
  (define (func-iter-part a b c count)
    (if (= count (+ n 1)) a
        (func-iter-part (+ (- count 1) (* 2 b) (* 3 c)) a b (+ count 1))))
  (if (< n 3) n
      (func-iter-part 2 1 0 3)))


거의 같은데 루프를 한 번 더 도는 것만 다르죠. ㅋㅋ 그런데 이 문제에 대한 인터넷 해답을 보니, 인터넷에서의 해답이 제 답과 조금 다르군요. 왜 그런가 잠시 생각해봤는데... 책에 오타가 있습니다 ㅎㅎ

To English Readers: There's typo in the exercise 1.11 of korean version of SICP. So. ignore the above answer - the answer for the 'wrong' question. Correct answer is given below (only the iterative version of the answer. I didn't give the recursive version of the answer, because it's too easy).

오타가 있어도 문제가 안풀리는 건 아닙니다만, 아무튼 답은 조금 달라집니다. 원서에 실린 문제 공식은 f(n) = (n-1) + 2f(n-2) + 3f(n-3)이 아니라 f(n) = f(n-1) + 2f(n-2) + 3f(n-3) 입니다. (한글판에는 f가 빠졌습니다.) f가 있을 경우의 해답은 다음과 같습니다. 역시 반복 프로세스의 경우만 싣습니다. 재귀적 프로세스의 경우에는 답이 뻔해서...

(define (f-b n)
  (define (f-b-iter a b c count n)
    (if (= count n) a
        (f-b-iter (+ a b c) (* 2 a) (* 3 (/ b 2)) (+ 1 count) n)))
  (f-b-iter 2 2 0 2 n))




사용자 삽입 이미지


이제 조금 익숙해지긴 했습니다만, 그래도 어렵긴 어렵군요. ㅋㅋ

신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 어쩐지 이상하다 했습니다.OTL....
    저는 n 파라메터를 따로 만들었는데, 앞에서 배운 블록구조 안에 숨겨서 변수를 그대로 쓸 수 있다는 것을 깜박했습니다.
    좋은 정보 고맙습니다.^^

    2008.01.04 10:54 신고 [ ADDR : EDIT/ DEL : REPLY ]

Books by Example/SICP2007.11.09 00:13
밤마다 한시간씩 SICP 문제를 풀어보고 있습니다. 오늘은 1.8을 풀어봤습니다. Scheme 언어에 익숙해지려면 아무래도 시간이 좀 많이 걸리겠군요. 문제 1.8은 이렇습니다.

세제곱근 cube root를 구하는 뉴튼 법은, x의 세제곱근에 가까운 값을 y라고 할 때 다음 식에 따라 y보다 더 가까운 값을 계산하는 것이다.

(x + y^2 + 2y) / 3

제곱근 프로시저처럼, 이 식을 써서 세 제곱근 프로시저를 짜보자.


글쎄 뭐 짜는 것 까지는 좋습니다. 다음과 같은 코드를 작성했습니다.

(define (cube_root x)
  (if (or (= x 0) (< x 0)) 0 (cube_root_iter 1.0 x)))

(define (cube_root_iter guess x)
  (if (good_enough? guess x) guess (cube_root_iter (improve guess x) x)))

(define (good_enough? guess x) (< (/ (abs (- (cube guess) x)) x) 0.01))

(define (cube x) (* x x x))

(define (improve y x) (+ (/ x (* 3 (* y y))) (/ (* 2 y) 3)))

(cube_root 5)


이 간단한 코드를 짜는 데만도 한시간이 걸렸습니다. 그런데 처음에는 이상하게 값이 잘 안나오고 무한루프에 빠지더군요. 의심가는 데가 있어서 google에게 물어봤는데, 아무래도 책(번역판)에 나온 뉴튼법 공식이 좀 잘못된 것 같습니다. 다음과 같이 되어야 할 것 같습니다. (책에 나온 수식의 첫 번째 +가 /로 바뀌면 됩니다.)

사용자 삽입 이미지

위의 코드에서 빨간색으로 표시된 부분이, google이 알려준 뉴튼법 공식에 따라 수정된 부분입니다. 이렇게 고치고 나니, 프로그램이 정상적인 결과를 내 놓았습니다.

이 오류가 한글판의 오류인지 아니면 원서의 오류인지 잘 모르겠어서 구글신에게 다시 물어봤습니다. 한글판의 오류입니다. -_-; 좋은 책입니다만, 40페이지를 넘어가기도 전에 오류를 하나 발견하고 나니 어쩐지 맥이 빠지는 기분입니다[각주:1].

이런 기분인거냐?

이런 기분인거냐?



아무튼, 매일 잠들기 전에 하나씩 풀어볼 문제가 생겼다는건 기분 좋은 일이로군요. 아 이제 선형 대수학 책도 봐야하는데... -_-
 

  1. 역자분들의 노고를 폄하하거나 할 의도가 없음을 밝혀둡니다. 어쨌든 좋은 책이고, 사람이란 실수를 하게 마련이니까요. [본문으로]
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. Programming Pearls 를 다 보고 이 책을 보려고 작정하고 있습니다. 나중에 연습 문제 풀 때 여기 자주 와야 되겠네요. 전 이거 두권이면 올 겨울은 그냥 지나갈 듯 합니다. ㅎㅎ

    2007.11.09 10:29 신고 [ ADDR : EDIT/ DEL : REPLY ]
  2. 명백한 오타네요. ㅡㅡ;;
    사람의 일이라 피하기 힘들다지만... 이런 사항이 보고될 때마다 가슴이 두근두근 댑니다.
    또 다른 대형 사고는 없는지.... 얼마나 더 지나야 안심할 수 있을런지.... 휴~

    지적하신 사항은 오탈자 사이트에 반영해 놓겠습니다.

    2007.11.09 15:48 신고 [ ADDR : EDIT/ DEL : REPLY ]
  3. 어쩐지 제가 뉴튼법으로 구한 식과 책에 적혀있는 것이 다르다고 했습니다.OTL....

    2007.12.18 12:35 신고 [ ADDR : EDIT/ DEL : REPLY ]
  4. 저도 같은 일을 겪었어요. 어쩐지 값이 안 나와서 뒷장의 뉴튼 부분을 참고하니 풀리더라고요. :)

    2008.08.31 15:44 신고 [ ADDR : EDIT/ DEL : REPLY ]

Books by Example/SICP2007.11.06 00:38
예전같으면 거뜬히 풀었을것도 같은데 (정말?) 이제 답 근처까지 가는건 가능해도 정답을 맞추는게 잘 안되네요. 문제는 이렇습니다. 다음의 소스 코드를 보면 sqrt-iter를 정의하면서 if를 사용한 부분이 있는데, 이 if 대신 new-if (이 함수의 정의도 소스 코드에 포함되어 있습니다)를 사용하면 어떻게 되느냐는 겁니다.

new-if는 코드를 보면 알 수 있듯이, if가 하는 일을 흉내내는 '함수'이고, sqrt-iter는 sqrt 함수, 즉 제곱근을 구하는 함수를 구현하기 위해 내부적으로 사용된 함수입니다.

(define (sqrt-iter guess x)
  (if (good-enough? guess x)
      guess
      (sqrt-iter (improve guess x) x)))

(define (new-if predicate then-clause else-clause)
  (cond (predicate then-clause)
        (else else-clause)))

(define (improve guess x)
  (average guess (/ x guess)))

(define (average x y)
  (/ (+ x y) 2))

(define (good-enough? guess x)
  (< (abs (- (square guess) x)) 0.001))

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

(define (sqrt x)
  (sqrt-iter 1.0 x))

(sqrt 2)  ==> 실행 결과로 1.4 어쩌구... 의 값을 내놓습니다.



답의 힌트는 윗 단락의 밑줄 그은 부분에 있습니다. new-if로 if가 하는 일을 대체할 수 있을 것 같지만, 문제가 그리 간단치 않습니다. Scheme 함수는 함수 body를 수행하기 전에, 인자들을 전부 evaluation합니다. 그러니 new-if의 세 인자도 new-if 수행 전에 전부 evaluation되어야 합니다.

따라서, 위의 코드에서 sqrt-iter 안에서 사용된 if를 new-if로 대체하게 되면, 그 세 번째 인자로 주어진 (sqrt-iter ...) 부분을 먼저 evaluation 해야하고, 그 결과로 재귀 호출이 발생하고, new-if가 다시 호출됩니다. 그 결과로 무한루프가 발생하고, 메모리 제한 조건을 적절히 설정해 두지 않았다면 Scheme 시스템이 뻗습니다.


아 진땀

아 역시 그런거였나?



그런데, 이 정도의 답도 빨리 못 내어 놓는 걸 보니 제 머리가 굳긴 굳은것 같군요. -_-; 앞으로 연습문제를 좀 충실히 풀어봐야겠습니다. 굳은 머리를 풀려면...


신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 전 처음에 무한반복을 예상했으나
    코드가 제대로 실행되는 것을 보고 당황했습니다.
    알고보니 기존의 sqrt-iter 프로시저에 if 대신 new-if로 바꾸지 않았더군요.OTL....
    그것도 모르고 '세상 참 신기하네..'라며 감탄하고 있었다니..OTL....

    sqrt-iter 프로시저에서 else-clause에 있는 sqrt-iter이 재호출되기 때문이 맞죠?
    메모리 제한을 걸지 않고 별 생각없이 구경하고 있다가 재부팅할 뻔했습니다.OTL.....

    2007.12.18 10:39 신고 [ ADDR : EDIT/ DEL : REPLY ]
  2. 아아 이런 .... OTL

    sqrt 를 정의 하지도 않고 빌트인 sqrt 를 써서 .....

    "이게 안되야하는데 왜 될까?" 하고 삽질했습니다 ㅋ

    2007.12.26 06:27 신고 [ ADDR : EDIT/ DEL : REPLY ]
  3. 디버깅 중에 good-enough?의 리턴이 참이 되는되도 guess가 아닌
    sqrt-iter로 계속 넘어가게 되어서 생각중이었는데 답은 함수의 동작에
    있었군요....ㅡㅡㅋ Scheme을 조금 더 공부해야 겠네요...^^

    2008.02.01 00:43 신고 [ ADDR : EDIT/ DEL : REPLY ]
  4. 낭만고양이님의 "Scheme 함수는 함수 body를 수행하기 전에, 인자들을 전부 evaluation합니다."
    라는 문장을 보고 순간 "아차;" 싶었습니다-_-;
    scheme이 기본적으로 인자를 먼저 계산하는 메소드를 채택하고 있다는 사실을
    잊어버리고 있었던채;;;
    여튼, 좀 속을 끙끙 앓고 있었는데 덕분에 명쾌한 답변이 되었던것 같습니다^^

    2008.03.29 18:37 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 도움이 되었다니 기쁘네요.
      이 책 놓고 있은지 꽤 오래 되었는데,
      다시 좀 봐야겠습니다. 책이 커서 그런지, 보는 중간에
      이런 일 저런 일 참 많이 생기네요.. ㅎㅎ

      2008.03.30 09:10 신고 [ ADDR : EDIT/ DEL ]

Books by Example/SICP2007.11.05 23:04
"컴퓨터 프로그램의 구조와 해석(이하 SICP)"에 대한 서평 아닌 서평을 일전에 올린 적이 있었습니다. 그 글을 올리고 한동안 책을 들춰보지 않았었는데요. 오늘 갑자기 그 책에 다시 손을 대게 되었습니다. 이러다가 평생 제대로 된 책 한권 다 읽지 못할지도 모른다, 는 공포심 같은 것이 들었다고나 할까요. 제 자신의 게으름에 물릴 대로 물렸다, 뭐 그런 겁니다.

SICP는 Scheme이라는 Lisp 언어를 대상으로 하고 있습니다. 고백하건대 저는 학부때 프로그래밍 언어 특론을 중도에 수강 포기했었습니다. Lisp 언어의 근간을 이루는 Lambda Calculus를 전혀 이해하지 못했기 때문이죠. Wikipedia의 Lambda Calculus 관련 페이지에서 한 단락을 인용해 보겠습니다.

The Lambda Calculus can be thought of as an idealized, minimalistic programming language. It is a close cousin of the Turing Machine, another minimalist abstraction capable of expressing any algorithm. The difference between the two is that the Lambda Calculus takes a functional view of algorithms, while the original Turing machine takes an imperative view. That is, a Turing machine maintains 'state' - an arbitrary long 'notebook' of symbols that can change from one instruction to the next. The imperative paradigm can be seen in programming languages like C or Basic. By contrast, the Lambda Calculus is stateless, it deals exclusively with functions which accept and return data (including other functions), but produce no side effects in 'state' and do not make alterations to incoming data (immutability.) The functional paradigm can be seen in modern languages like Lisp, Scheme and Haskell


그런데 이제와서 골치아프기까지 한데다 "먹고 사는 문제하고도 하등의 상관이 없는" 언어로 씌여진 책을 다시 공부해보겠다고 설치는 이유는 뭘까요? 첫 번째는 'Lisp나 lambda calculus라는 것이 생각보다는 어렵지 않더라', 는 깨달음인 것 같고, 두 번째는 ... 설명하기 좀 곤란하니까 넘어가도록 하죠 ^^;

아무튼, 이 책을 읽으려면 Scheme 컴파일러, 디버거 등등의 시스템이 필요합니다. 잘 알려진 Scheme 시스템으로 MIT/GNU Scheme이 있고 PLT-Scheme이 있는데, 둘 다 Windows에서는 잘 깔립니다. Linux에서는 Ubuntu라면 모르겠지만 Fedora라면 깔기가 좀 난감합니다. 설치 메뉴얼 대로 해봐도 다 잘 안되죠.  (제 리눅스는 Fedora Core 6 입니다) 거기다 MIT/GNU Scheme의 Windows 인터페이스(Erwin이라고 부릅니다만)는 하필이면 제가 익숙치 않은 Emacs 기반의 인터페이스입니다. -_-;

그러니, Windows에서건 Linux에서건 PLT-Scheme쪽이 더 낫습니다. 설치도 간단하고 (Windows에서는 인스톨러만 실행하면 되고, FC 6에서는 yum install plt-scheme이라고만 하면 됩니다) 인터페이스도 훨씬 더 직관적입니다.

PLT-Scheme 실행 화면

PLT-Scheme 실행 화면


위의 그림은 제 집 컴퓨터(Windows XP)에서 PLT-Scheme을 돌려 본 화면입니다. 리눅스가 깔린 회사 노트북(LM 70)에서도 설치해서 돌려봤는데, 저거랑 똑같은 형태로 실행됩니다. -_-

PLT-Scheme의 GUI는 DrScheme이라고 불립니다. MzScheme이라고 GUI가 없는 형태의 cheme 구현도 포함되어 있는데, MzScheme은 Unix에서 좀 더 사용하기가 편합니다.

http://www.plt-scheme.org/에서 다운받아 사용할 수 있습니다.

신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 저두 그 책을 공부할려고 , scheme 을 깔려고 했던게 기억나네요. 트랙은 저는 원래 emacs 유저라 emacs 에다 붙이는 걸 남깁니다. (__

    2007.11.20 15:56 신고 [ ADDR : EDIT/ DEL : REPLY ]
  2. 반갑습니다. 뉴스2.0을 타고 왔습니다.
    오늘부터 해당 책으로 동아리에서 스터디에 들어갑니다.
    (책은 잘 모르고 하자니 따라하는 수준...OTL.....)
    해당 임플리멘테이션이 페도라에는 잘 설치가 되지 않는군요.OTL...
    (전 Fedora 7에서 오늘 8으로 올릴 생각입니다.)
    좋은 정보 고맙습니다.^^

    2007.11.23 12:22 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 아. 반갑습니다. 스터디 하신다니 좋으시겠군요.
      PLT-Scheme이면 페도라에도 잘 깔릴텐데 이상하군요.
      아무튼 잘 되길 바랍니다. :-)

      2007.11.23 12:55 신고 [ ADDR : EDIT/ DEL ]
  3. 멋지십니다. >_<//
    저도 이번주부터 학교 친구들 모아서 스터디에 들어갑니다.
    이런 뜻있는 분들이 모두 모인다면 정말 공부하는데 도움이 될듯 합니다.
    응원해주세요! -_- 중간에 포기하지않기를요 ^^

    앞으로 낭만고양이님 신세좀 많이 지겠습니다. ^^

    2007.12.17 14:31 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 스터디하신다니 부럽군요. 전 혼자 하려니 힘듭니다 ㅎㅎ 꼭 끝까지 완독하시길 바랍니다! 화이팅~

      2007.12.17 16:40 신고 [ ADDR : EDIT/ DEL ]
  4. 퍼갑니다^^ 참 좋은 정보 들이 많군요~~^^ㄳㄳ

    2008.07.23 01:30 신고 [ ADDR : EDIT/ DEL : REPLY ]