Go 로 읽는 SICP Part 1: 마법사 책은 왜 아직도 살아 있나
이 글은 Claude Opus 5 를 이용해 초안이 작성되었으며, 이후 퇴고를 거쳤습니다.
프로그래밍 책의 유효기간은 보통 짧습니다. 5년이면 예제가 안 돌아가고, 10년이면 권하기가 민망해집니다.
그런데 1984년에 초판이 나온 책 하나가 아직도 목록에 남아 있습니다. 표지에 마법사가 그려져 있어서 “마법사 책(Wizard Book)” 이라고 불리는 Structure and Interpretation of Computer Programs, 줄여서 SICP 입니다.
이 시리즈는 SICP 를 Go 로 다시 걸어 보는 14부작입니다. 원서는 Scheme 으로 쓰였고, 2022년에 나온 공식 JavaScript 판도 있습니다. 둘 다 훌륭한데, 둘 다 이 책이 요구하는 언어 기능을 이미 갖춘 언어입니다. Go 는 그렇지 않습니다. 그래서 재미있습니다. 없는 기능을 손으로 만들어야 하는 지점마다, 원서가 무엇을 당연시하고 있었는지가 드러납니다.
이번 편은 코드가 거의 없습니다. 책과 저자를 소개하고, 다섯 개 장의 지형도를 그리고, Go 가 이 책에 적합한 언어인지 를 실측으로 판정합니다. 마지막에 맛보기 코드 하나를 돌려 봅니다.
1. 보라색 표지의 마법사 책#
먼저 서지 사항입니다.
| 항목 | 내용 |
|---|---|
| 제목 | Structure and Interpretation of Computer Programs |
| 저자 | Harold Abelson, Gerald Jay Sussman, with Julie Sussman |
| 초판 / 2판 | 1984년 / 1996년 |
| 출판사 | MIT Press |
| 2판 ISBN | 0-262-51087-1 |
| 라이선스 | CC BY-SA 4.0 — 전문이 합법적으로 무료 공개 |
| 서문 | Alan J. Perlis |
마지막 두 줄이 이 시리즈의 전제입니다. 저자들이 2판 텍스트를 Creative Commons 라이선스로 풀어 놓았기 때문에, 원문을 인용하고 예제를 옮기는 데 저작권 문제가 없습니다. HTML·PDF·EPUB 판본이 여러 곳에 미러링되어 있습니다.
이 책은 원래 MIT 6.001 “Structure and Interpretation of Computer Programs” 의 교재였습니다. MIT 전기공학·컴퓨터과학과의 첫 필수 과목이었고, Sussman 과 Abelson 이 1980년에 만들었습니다.
책이 유명해진 방식이 특이합니다. 대학 교재가 흔히 그렇듯 강의실 안에서만 소비된 게 아니라, 강의실 밖에서 더 오래 읽혔습니다. MIT 학생이 아닌 사람들이 혼자 읽고, 스터디를 만들고, 연습문제 풀이를 인터넷에 올리기 시작했습니다. 그 결과 “6.001 교재” 보다 “SICP” 라는 약칭이 훨씬 널리 알려졌습니다.
2. 누가 썼는가#
Harold Abelson. MIT 전기공학·컴퓨터과학 교수. 수학 박사(MIT, 1973) 출신으로, 나중에 어린이용 프로그래밍 환경 Logo 와 그 후속 작업에 깊이 관여했습니다. 프로그래밍 교육에 대한 관심이 이 책의 서술 방식에 직접 반영되어 있습니다. Creative Commons 와 Free Software Foundation 의 창립 이사이기도 합니다. 이 책이 CC 라이선스로 풀린 배경에 저자 본인의 성향이 있습니다.
Gerald Jay Sussman. MIT 교수. Guy Steele 과 함께 1975년에 Scheme 을 만든 사람입니다. 이 책이 Scheme 으로 쓰인 이유가 여기 있습니다. 저자가 언어 설계자 본인이니, 언어의 어느 기능이 왜 그 자리에 있는지를 아는 상태로 교재를 쓴 셈입니다. 이후 물리학 교육으로 관심을 옮겨 Structure and Interpretation of Classical Mechanics 를 냈습니다. 제목이 비슷한 게 우연이 아닙니다. 같은 방법론을 고전역학에 적용한 책입니다.
Julie Sussman. 표지에 “with Julie Sussman” 으로 올라간 이름입니다. 통상적인 감사의 말이 아니라 저자 표기입니다. 이 책의 문장이 교재답지 않게 잘 읽히는 데 상당한 기여를 한 것으로 알려져 있습니다. JavaScript 판에도 같은 자격으로 참여했습니다.
Alan J. Perlis. 서문을 쓴 사람입니다. 1966년 제1회 튜링상 수상자이고, “Epigrams on Programming” 으로 유명합니다. 이 서문은 프로그래밍 문헌에서 가장 많이 인용되는 텍스트 중 하나입니다.
“It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures.”
— 하나의 자료구조 위에서 100개의 함수가 동작하는 편이, 10개의 자료구조 위에서 10개의 함수가 동작하는 것보다 낫다.
“Pascal is for building pyramids—imposing, breathtaking, static structures built by armies pushing heavy blocks into place. Lisp is for building organisms—imposing, breathtaking, dynamic structures built by squads fitting fluctuating myriads of simpler organisms into place.”
— Pascal 은 피라미드를 짓는 언어다. 웅장하고 숨막히지만, 무거운 블록을 밀어 넣는 군대가 만든 정적인 구조물이다. Lisp 은 생물을 기르는 언어다. 역시 웅장하고 숨막히지만, 끊임없이 변하는 무수한 단순 생물들을 소분대가 조립해 만든 동적인 구조물이다.
두 인용이 이 책의 태도를 요약합니다. 첫째는 표현을 통일하고 연산을 늘려라 는 것, 둘째는 프로그램을 조립물이 아니라 자라나는 것으로 보라 는 것입니다. 두 문장 모두 40년 뒤의 언어 설계 논쟁에 그대로 갖다 붙일 수 있습니다.
3. 왜 40년이 지나도 읽히는가#
3.1 이 책은 언어 교재가 아닙니다#
SICP 를 “Lisp 배우는 책” 으로 알고 펼치면 당황합니다. Scheme 문법 설명은 1장 앞부분 몇 쪽으로 끝납니다. 정말로 끝납니다. 그 뒤로는 문법 이야기가 나오지 않습니다.
Perlis 의 서문에도 이 점이 못박혀 있습니다.
“Note that this is a text about programming, unlike most Lisp books, which are used as a preparation for work in artificial intelligence.”
이 책이 다루는 것은 복잡도를 어떻게 통제하는가 입니다. 사람의 머리에 한 번에 들어오는 양은 정해져 있는데 시스템은 그보다 큽니다. 그 격차를 메우는 도구가 추상화이고, 이 책은 그 도구를 세 가지 층위에서 반복해 보여 줍니다.
3.2 같은 이야기를 세 층위에서 반복합니다#
1장은 프로시저 로 추상화합니다. 2장은 데이터 로 추상화합니다. 4장은 언어 자체 를 만들어서 추상화합니다.
세 번 다 구조가 같습니다. 세부를 이름 뒤에 감추고, 그 이름만으로 다음 층을 짓습니다. 다른 점은 감추는 대상이 무엇이냐뿐입니다. 이 반복이 의도적이고, 반복을 세 번 겪고 나면 “추상화” 라는 단어의 의미가 달라집니다.
3.3 평가기를 직접 만듭니다#
4장에서 이 책은 Scheme 으로 Scheme 인터프리터를 씁니다. 20~30줄짜리 eval 과 apply 두 함수가 서로를 부르면서 언어 하나를 정의합니다.
이 경험이 남기는 것은 특정 기술이 아닙니다. 언어와 프로그램 사이에 넘을 수 없는 선이 없다 는 감각입니다. 여러분이 매일 쓰는 언어도 누가 저렇게 짠 것이고, 마음에 안 드는 부분이 있으면 여러분도 저렇게 짤 수 있다는 것입니다.
그리고 5장에서 그 인터프리터를 레지스터 머신 명령어까지 내려보냅니다. 고수준 언어의 함수 호출이 스택 위에서 실제로 무슨 일을 하는지, 꼬리 재귀가 왜 공간을 안 먹는지가 여기서 기계적으로 드러납니다. 위에서 아래까지 끊기는 데 없이 이어집니다. 이런 구성의 입문서는 지금도 드뭅니다.
3.4 그런데 MIT 는 이 과목을 폐지했습니다#
여기서 균형을 맞춰야 공정합니다. 저자들 본인이 이 과목을 접었습니다.
MIT CSAIL 의 2007년 12월 9일 공지는 이렇게 적고 있습니다. 6.001 은 2007년 가을학기를 마지막으로 MIT 교육과정에서 폐지 되었고, Sussman 과 Abelson 이 1980년에 만든 이 과목은 27년을 채우고 끝났습니다. 후속 과목은 Python 을 씁니다.
폐지 이유에 대해 Sussman 이 했다는 설명이 널리 인용됩니다. 요지는 이렇습니다. 1980년의 프로그래밍은 자기가 완전히 이해하는 작은 부품들을 단순한 방법으로 조립해 큰 것을 만드는 일이었지만, 지금은 아니라는 것입니다. 지금은 누가 썼는지도 모르는 라이브러리의 부실한 문서를 뒤지면서 시간을 보냅니다. 그래서 6.001 이 가르치려던 종류의 공학이 더 이상 지금의 공학이 아니라는 이야기입니다.
다만 이 발언은 2009년 컨퍼런스 현장에서 나온 말을 참석자가 옮긴 블로그 기록 이 원출처입니다. Sussman 본인이 쓴 글이 아니므로, 인용할 때 전언임을 밝히는 것이 정직합니다.
이 반론은 받아들일 만합니다. SICP 는 입문 교재로는 확실히 부적합 합니다. 프로그래밍을 처음 배우는 사람에게 이 책을 던지는 것은 잔인한 일입니다.
그런데 같은 이유로 두 번째나 세 번째 책으로는 오히려 값이 오릅니다. 라이브러리를 조립해서 돌아가는 것을 만들 줄 알게 된 다음, “내가 지금 뭘 하고 있는지 모르겠는데” 라는 감각이 찾아올 때 읽으면 정확히 그 자리를 메웁니다. 프레임워크가 대신 해 주던 결정들이 실은 어떤 결정이었는지가 보이기 시작합니다.
그리고 2026년의 사정을 하나 덧붙이면, 코드를 생성하는 쪽은 점점 저렴해지는데 읽고 판정하는 쪽은 그렇지 않습니다. 생성된 코드가 왜 이렇게 생겼는지, 이 추상화가 값을 하는지 판정하는 능력은 여전히 사람 쪽에 있습니다. SICP 가 훈련시키는 것이 정확히 그 능력입니다.
4. 다섯 개의 장#
책은 다섯 장이고, 장마다 추상화의 재료가 바뀝니다.
flowchart TD
C1["1장<br/>프로시저로 만드는 추상화<br/><small>계산 과정의 모양</small>"]
C2["2장<br/>데이터로 만드는 추상화<br/><small>복합 데이터와 표현</small>"]
C3["3장<br/>모듈성·객체·상태<br/><small>시간이 들어온다</small>"]
C4["4장<br/>메타언어적 추상화<br/><small>언어를 직접 만든다</small>"]
C5["5장<br/>레지스터 머신으로 계산하기<br/><small>기계까지 내려간다</small>"]
C1 -->|"조립할 대상을<br/>프로시저에서 데이터로"| C2
C2 -->|"값에 시간을<br/>도입한다"| C3
C3 -->|"언어 자체를<br/>대상으로 삼는다"| C4
C4 -->|"해석기를<br/>기계로 내려보낸다"| C5
style C1 fill:#90EE90,color:#000000
style C2 fill:#87CEEB,color:#000000
style C3 fill:#FFD700,color:#000000
style C4 fill:#FFA07A,color:#000000
style C5 fill:#DDA0DD,color:#000000
각 장을 조금 더 풀면 이렇습니다.
1장 — Building Abstractions with Procedures. 프로시저를 값 으로 다루기 시작합니다. 여기서 이 책의 가장 유명한 구분이 나옵니다. 재귀적 프로시저 와 재귀적 프로세스 는 다르다는 것입니다. 코드가 자기를 부르는 모양(프로시저)과, 실행 중 메모리가 실제로 자라는 모양(프로세스)은 별개입니다. 이 구분이 이 시리즈에서 Go 와 처음 충돌하는 지점이기도 합니다.
2장 — Building Abstractions with Data. cons·car·cdr 세 개로 시작해서 리스트, 트리, 기호식 미분, Huffman 부호화, 그리고 여러 표현을 동시에 지원하는 산술 시스템까지 갑니다. 후반부의 데이터 지향 프로그래밍 절은 Go 인터페이스 설계 이야기와 사실상 같은 내용입니다. 이 시리즈에서 궁합이 가장 좋은 대목입니다.
3장 — Modularity, Objects, and State. 대입(set!)을 도입하고, 그 대가를 계산합니다. 치환 모델이 깨지고 환경 모델 이 필요해집니다. 후반부에서 동시성과 스트림(지연 평가된 무한 리스트)을 다룹니다. Go 의 고루틴과 채널이 여기에 어울릴 것 같지만, 어울리는 부분과 전혀 다른 부분이 갈립니다. Part 9 의 주제입니다.
4장 — Metalinguistic Abstraction. 메타순환 평가기, 게으른 평가기, amb 비결정성 평가기, 논리 프로그래밍 질의 시스템. 이 책의 정점이고, Go 로 옮길 때 가장 많은 일을 손으로 해야 하는 곳입니다.
5장 — Computing with Register Machines. 레지스터 머신 시뮬레이터를 만들고, 그 위에 4장의 평가기를 다시 구현하고, 마지막에 컴파일러를 붙입니다. 가비지 컬렉션도 여기서 직접 만듭니다. 역설적으로 Go 와 궁합이 가장 좋은 장 입니다.
5. 왜 Go 인가, 그리고 Go 로 안 되는 것#
이 시리즈는 코드를 전부 Go 로 씁니다. 그런데 정직하게 말하면, Go 는 SICP 를 위해 설계된 언어와 정반대 방향에 있는 언어입니다. Scheme 은 문법이 거의 없고 표현식만 있고 재귀를 언어 차원에서 보장합니다. Go 는 문장 지향이고, 삼항 연산자도 없고, 재귀에 대한 보장이 없습니다.
그럼에도 Go 로 가는 이유가 있고, 넘어가지 못하는 벽도 있습니다. 세 곳을 미리 밝혀 둡니다.
5.1 마찰 하나 — Go 에는 꼬리 호출 최적화가 없습니다#
SICP 1.2.1 의 핵심 주장은 이것입니다. 재귀적으로 생긴 프로시저가 반복적인 프로세스를 만들 수 있다. 마지막 동작이 자기 호출뿐이면(꼬리 호출) 돌아가서 할 일이 없으므로, 처리기는 호출 프레임을 새로 쌓지 않고 재사용할 수 있습니다. Scheme 표준은 이것을 보장 합니다.
Go 는 보장하지 않습니다. 말로 하는 대신 재 보았습니다. go1.26.0 darwin/arm64 에서, 꼬리 재귀로만 이루어진 누적 합산 함수의 runtime.MemStats.StackInuse 입니다.
재귀 깊이 n | StackInuse |
|---|---|
| 1,000 | 0.28 MB |
| 100,000 | 2.22 MB |
| 10,000,000 | 256.22 MB |
깊이에 선형 비례 합니다. 프레임이 그대로 쌓입니다. 그리고 최대 스택을 넘기면 이렇게 끝납니다.
runtime: goroutine stack exceeds 16777216-byte limit
fatal error: stack overflow
64비트에서 기본 상한은 1 GB 입니다. 즉 Go 에서는 꼬리 재귀도 결국 죽습니다. SICP 1.2.1 의 문장을 Go 로 옮기면 그대로 거짓이 됩니다.
대응은 손으로 루프로 바꾸는 것입니다. 시시해 보이지만 여기에 반전이 있습니다. 5장의 명시적 제어 평가기가 다루는 주제가 정확히 “그 변환은 왜 기계적으로 가능한가” 입니다. 1장에서 손으로 하던 일이 5장에서 자동화되어 돌아옵니다. Go 를 쓰면 이 회수가 훨씬 선명해집니다.
5.2 마찰 둘 — Go 에서 프로그램은 데이터가 아닙니다#
Scheme 에서 (+ 1 2) 는 “1과 2를 더하라” 이기도 하고 “심볼 +, 숫자 1, 숫자 2 로 이루어진 세 원소 리스트” 이기도 합니다. 같은 것입니다. 그래서 4장의 평가기가 짧습니다. 파싱할 게 없습니다. 리스트를 받아 첫 원소를 보고 분기하면 됩니다.
Go 에는 이 성질이 없습니다. Go 소스는 문자열이고, 프로그램을 데이터로 다루려면 렉서와 파서를 직접 만들어야 합니다.
이건 Go 만의 문제가 아닙니다. 공식 JavaScript 판도 같은 벽에 부딪혔고, 그 서문에서 “프로그램을 데이터 구조로 직접 표현하는 것을 더 이상 당연시할 수 없어서” 4장에 프로그램 파싱 절을 새로 넣었다고 밝히고 있습니다. 즉 Scheme 이 아닌 언어로 SICP 4장을 하는 사람은 누구나 이 비용을 냅니다.
부작용이 나쁘지만은 않습니다. 파서를 직접 쓰면 “언어를 만든다” 는 일이 실제로 어떤 노동인지 알게 됩니다. 원서는 그 노동을 건너뛰게 해 줬을 뿐입니다.
5.3 마찰 셋 — Go 에는 일급 연속이 없습니다#
4.3 절의 amb 평가기는 백트래킹 을 언어 기능으로 만듭니다. (amb 1 2 3) 이 세 값 중 하나를 고르고, 뒤에서 모순이 나면 시간을 되감아 다른 값을 고릅니다. 원서는 이것을 성공 연속과 실패 연속 두 개를 넘기는 방식으로 구현합니다.
Go 에는 call/cc 가 없습니다. 그런데 이건 실제로는 문제가 되지 않습니다. 4.3 이 필요로 하는 연속은 우리가 만든 인터프리터 안의 연속이고, 그건 Go 클로저로 표현할 수 있습니다. 원서도 호스트 Scheme 의 call/cc 를 쓰지 않습니다.
다만 클로저 체인이 깊어지면 5.1 의 문제와 다시 만납니다. 깊은 탐색에서 스택이 자랍니다. Part 12 에서 이 지점을 정면으로 다룹니다.
5.4 반대로 궁합이 좋은 곳#
마찰만 있으면 언어 선택이 잘못된 것입니다. 그렇지 않습니다.
| 원서의 주제 | Go 와의 궁합 |
|---|---|
| 2.4~2.5 태그드 데이터·데이터 지향 프로그래밍 | 매우 좋음. 인터페이스 + 타입 스위치 + 디스패치 테이블. Go 설계 철학과 같은 이야기 |
| 3.1~3.3 지역 상태·가변 데이터 | 좋음. 클로저와 포인터로 자연스럽게 표현 |
| 3.4 동시성 | 좋음. 원서는 언어 지원 없이 말로 설명하는데, Go 에서는 실제로 실행 해서 경쟁 조건을 볼 수 있음 |
| 5장 레지스터 머신·GC | 매우 좋음. 명시적 상태와 배열을 다루는 명령형 시뮬레이터. Go 가 잘하는 일 |
특히 3.4 는 Go 로 하는 편이 원서보다 낫습니다. 원서는 1996년 언어로 동시성을 다루느라 사고 실험에 머무는데, Go 에서는 go test -race 로 경쟁 조건을 실제로 잡아낼 수 있습니다.
5.5 그래도 대안 언어를 고른다면#
Go 로 못 할 정도는 아니지만, 다른 선택지의 값을 매겨 두는 게 공정합니다. Lisp 계열과 JavaScript 를 제외하고 지금 널리 쓰이는 언어 중에서 보면 이렇습니다.
| 언어 | 장점 | 단점 | 평가 |
|---|---|---|---|
| Python | 동적 타입·일급 함수·간결함. MIT 후속 과목이 실제로 택한 언어 | 꼬리 호출 최적화를 의도적으로 거부. 재귀 깊이 기본 상한이 낮음 | 1순위. 접근성이 압도적 |
| OCaml | 대수적 자료형 + 패턴 매칭 + 꼬리 호출 보장. 4~5장 평가기 구현에 이보다 나은 게 드묾 | 사용자 층이 얇음 | 4~5장 충실도 기준 1순위 |
| Kotlin | tailrec 키워드로 꼬리 재귀를 보장. sealed class 로 대수적 자료형 표현 | JVM 초기 설정 부담 | 좋은 차선 |
| Rust | 대수적 자료형·패턴 매칭 훌륭 | cons 셀, 가변 리스트, 환경 체인 전부가 소유권과 싸움. Rc<RefCell<T>> 가 도배됨 | 비추천. SICP 를 배우는 데 인지 부하가 두 배 |
정리하면 접근성은 Python, 4~5장 충실도는 OCaml 입니다. Rust 는 언어가 나빠서가 아니라, 이 책의 주제와 Rust 의 주제가 동시에 머리를 요구해서 추천하지 않습니다.
그러면 왜 Go 인가. 마찰이 교육적이기 때문입니다. Scheme 으로 읽으면 1.2.1 의 꼬리 재귀 이야기가 그냥 참인 문장으로 지나갑니다. Go 로 읽으면 그게 언어가 해 주고 있던 일이었음을 스택 그래프로 보게 됩니다. 없는 것을 손으로 만들어 봐야 그게 무엇이었는지 압니다.
6. 맛보기 — SICP 1.1.7 을 Go 로#
말이 길었으니 코드를 하나 돌려 보겠습니다. 원서 1.1.7 절, 뉴턴법으로 제곱근을 구하는 예제입니다. 이 책의 첫 번째 “제대로 된” 프로그램입니다.
package main
import "fmt"
func abs(x float64) float64 {
if x < 0 {
return -x
}
return x
}
func average(a, b float64) float64 { return (a + b) / 2 }
// x/guess 와 guess 의 평균이 더 나은 추측이다.
func improve(guess, x float64) float64 { return average(guess, x/guess) }
func goodEnough(guess, x float64) bool { return abs(guess*guess-x) < 0.001 }
func sqrtIter(guess, x float64) float64 {
if goodEnough(guess, x) {
return guess
}
return sqrtIter(improve(guess, x), x)
}
func sqrt(x float64) float64 { return sqrtIter(1.0, x) }
원서의 Scheme 코드와 구조가 한 줄씩 대응합니다. 이름도 그대로 옮겼습니다. 그리고 이 코드에는 원서가 연습문제 1.7 로 지적한 결함이 그대로 살아 있습니다. 돌려 보면 이렇습니다.
x=9 guess=3.0000915541313802 iters=4 converged=true
x=100 guess=10.000000000139897 iters=7 converged=true
x=0.0001 guess=0.032308448330481222 iters=5 converged=true
x=1e+12 guess=1000000 iters=25 converged=true
x=1e+13 guess=3162277.6601683795 iters=200 converged=false
두 줄이 문제입니다.
x = 0.0001 의 정답은 0.01 인데 0.0323 을 내놓고 “충분히 좋다” 고 선언했습니다. goodEnough 가 절대 오차 0.001 을 쓰기 때문입니다. 정답 자체가 0.01 인 문제에서 0.001 은 느슨한 자가 아니라 아무것도 재지 못하는 자입니다.
x = 1e13 은 200번 돌려도 수렴하지 않았습니다. 반대 이유입니다. 답이 300만 근처인데 float64 가 그 크기에서 표현할 수 있는 간격이 0.001 보다 큽니다. guess*guess - x 가 0.001 아래로 내려갈 수 없으므로 조건이 영원히 거짓입니다. 원래 재귀 버전으로 이걸 돌리면 무한 루프에 빠집니다. 위 출력은 반복 상한을 걸어서 200에서 멈춘 것입니다.
이게 SICP 첫 장의 스타일입니다. 예제를 주고, 그 예제가 어디서 부서지는지를 연습문제로 묻습니다. 고정된 절대 임계값이 잘못된 추상화 라는 것이 요점입니다. 상대 오차로 바꾸면 두 문제가 함께 사라집니다. Part 2 에서 다룹니다.
한 가지 더 짚어 둘 것이 있습니다. sqrtIter 는 마지막 동작이 자기 호출뿐인 꼬리 재귀 입니다. Scheme 이라면 이 함수는 상수 공간에서 돕니다. Go 에서는 반복 횟수만큼 스택이 자랍니다. 여기서는 반복이 몇 번뿐이라 아무 일도 안 일어나지만, 이 차이가 다음 편의 주제입니다.
7. 시리즈 목차#
| Part | 다루는 범위 |
|---|---|
| 1 | 이 글. 책·저자 소개, 왜 지금도 읽히는가, 다섯 장 개관, Go 적합성 판단 |
| 2 | 1장 ① 프로시저 추상화, 치환 모델, 재귀 프로시저 vs 재귀 프로세스, TCO 부재 |
| 3 | 1장 ② 고차 함수·람다·클로저, 뉴턴법 일반화, Go 제네릭으로 본 추상화 |
| 4 | 2장 ① 데이터 추상화, 추상화 장벽, cons/car/cdr, 폐포 성질 |
| 5 | 2장 ② 계층 구조, 관례적 인터페이스(map/filter/reduce), 기호 데이터와 Huffman |
| 6 | 2장 ③ 태그드 데이터, 데이터 지향 프로그래밍 vs 메시지 패싱 |
| 7 | 3장 ① 대입과 지역 상태, 환경 모델 |
| 8 | 3장 ② 가변 데이터, 큐·테이블, 디지털 회로 시뮬레이터 |
| 9 | 3장 ③ 동시성과 스트림 — 채널이 SICP 스트림이 아닌 이유 |
| 10 | 4장 ① 메타순환 평가기 (1) — 파서와 핵심 eval/apply |
| 11 | 4장 ② 메타순환 평가기 (2) — 구문 분석 분리, 게으른 평가 |
| 12 | 4장 ③ amb 비결정성 평가기 |
| 13 | 5장 ① 레지스터 머신 시뮬레이터, 스택, 가비지 컬렉션 |
| 14 | 5장 ② 명시적 제어 평가기와 컴파일러 |
References#
1차 자료
- Abelson, H., Sussman, G. J., with Sussman, J. Structure and Interpretation of Computer Programs, 2nd ed. MIT Press, 1996. 전문 CC BY-SA 4.0 공개 — https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/6515/sicp.zip/index.html
- 2판 전문 HTML 판본 (목차·서문 인용 출처) — https://sarabander.github.io/sicp/html/
- Perlis, A. J. Foreword to SICP. New Haven, Connecticut. — 인용문은 위 전문의 Foreword 원문 그대로입니다.
- MIT CSAIL. “6.001 completes a twenty-seven year run.” 2007-12-09. https://www.csail.mit.edu/news/6001-completes-twenty-seven-year-run — 6.001 폐지 시점(2007년 가을학기)과 개설 연도(1980년)의 1차 출처입니다.
- Abelson, H., Sussman, G. J., Sussman, J.; adapted for JavaScript by Henz, M., Wrigstad, T. Structure and Interpretation of Computer Programs: JavaScript Edition. MIT Press, 2022. ISBN 978-0-262-54323-1. 전문 — https://sicp.sourceacademy.org/
- SICP JS 판 Preface — https://sicp.sourceacademy.org/chapters/prefaces03.html — 4·5장을 개정한 이유(
return문 처리, 프로그램의 데이터 표현을 당연시할 수 없음)의 출처입니다.
전언으로만 확인된 것
- Sussman 의 6.001 폐지 이유 설명은 2009년 컨퍼런스 현장 발언을 참석자가 옮긴 기록이 원출처입니다. 저자 본인이 쓴 글이 아닙니다. https://www.wisdomandwonder.com/link/2110/why-mit-switched-from-scheme-to-python
본문의 실측 데이터
- 꼬리 재귀 스택 사용량과
stack overflow메시지는go version go1.26.0 darwin/arm64에서 직접 측정한 값입니다. - 6절의 제곱근 출력값은 위 Go 코드를 실제로 실행한 결과입니다.