2009.02.01 08:09

LISP에 대한 생각들 -첫번째 이야기.



해커 문화의 뿌리를 찾아서 Part 1: 리스프가 탄생하기까지



안윤호안윤호 mindengine@freechal.com

필자는 아마추어 리눅스 커널 해커였으며 최근에 팹(Fab)이라는 책을 번역 출간했다. 컴퓨터의 여러 분야에 관심이 많고 컴퓨터와 문화의 인터페이스에도 관심이 많다.


2007년 4월 3일


'마법사 책'이라 불린 SICP

SICP(Structure and Interpretation of Computer Programs)는 한때 미국 주요 대학들의 컴퓨터학과 필수 과정 중 하나였다. 책은 매우 어려운 편이고 책의 연습문제라는 것들에는 우수한 컴퓨터 프로그래머들이 고민하던 문제들이 포함되어 있다. 그리고 다른 책과는 그 구성이 너무 다르다. 끝부분에 가면 메타 서큘러 실행기를 거쳐 언어의 컴파일러인지, 하드웨어의 컴파일러인지 경계가 애매한 지경에까지 이른다. 학생들이 당혹해 할 것은 틀림없다. SICP는 컴퓨터 교육의 패러다임을 바꾸어 놓았다는 평을 듣기도 한다.



SICP의 표지
그림 1. 마법사 책이라고 하는 SICP의 표지.
그림에 나온 람다(lambda)와 apply-eval 개념은 책을 관통하는 주제다. 책은 http://mitpress.mit.edu/sicp/에 온라인 문서로 공개되어 있다.

그래서 SICP에 대해서는 많은 사람들의 의견이 반반으로 갈린다. 생각하고 배울 점이 많은 책이라는 의견과 배울 것도 없으면서 시간만 낭비하게 하는 괴상한 책이라는 견해다. 한때 이 책을 필수 학점의 교재로 사용하던 학교에서는 학생들이 과정을 따라가는 일 자체에 공포심을 느꼈으며 불평도 대단했다. 시종일관 생각하게 만든다는 것이 공포심을 갖게 하는 요인이었다. 필자 역시 처음에는 책이 너무나 이상하다고 생각해서, 보다가 두 번이나 집어 던진 기억이 있다. 필자는 강의를 들은 것이 아니라 혼자서 공부했기 때문에 책의 배경을 이해하지 못했다. 책에 대한 재평가는 SICP와 관련된 메모들과 문서들, 그리고 문서들의 역사적인 맥락을 조금이나마 알게 되면서부터다. 그리고 컴퓨터에 대해 다시 생각하게 되었다.

책에 대해 불평하던 사람들 가운데 나중에 이 책을 다시 보거나 재평가하는 사람들이 꽤 있다. 그 중에는 조엘 스폴스키(Joel Spolsky)도 있었다. 조엘은 조엘 온 소프트웨어(Joel On the Software)라는 블로그로 유명한 사람이다. 조엘의 글 중에 “Perils on the Java School”은 미국 대학의 컴퓨터 학과가 너무 쉬운 것들만 다루려고 해서 수준 저하가 올 것이라는 내용이었다.
조엘 자신이 나이를 먹었다는 확실한 징조가 “요즘 아이들이” 어려워 보이는 것들을 하려고도, 할 수 있다고도 생각하지 않는다는 현상이라고 했다. 컴퓨터 학과에서 자료구조와 함수형 언어 같은 것을 심도 있게 가르치지 않기 때문에 평이한 학생들만을 만들어 내며, 학생들은 교과 과정이 어렵지 않기 때문에 많은 생각을 하지 않고 졸업한다. 그래서 평범한 프로그램만 만들어 내는 평범한 프로그래머만이 나올 것 같다는 내용이다(예전에는 자료구조나 함수형 언어 같은 것이 너무 어려워 고교 시절까지 스스로 우수하다고 생각했던 학생들이 자신의 능력을 진지하게 생각하고 과를 바꾸는 경우가 있었다는 것이다. 과정 자체가 사람들을 솎아내는 기능이 있었다).

이렇게 어려운 교과 중 하나가 MIT 학부 과정의 SICP다. 앞서 말했듯이 과거에는 주요 대학들의 표준 교재였다. 조엘은 블로그에서 이렇게 말하고 있다.

“코스의 난이도는 경이적이다. 처음 5번 정도의 강의에서 스킴(Scheme)의 대부분을 배우며 그것으로 다른 함수를 입력으로 받는 fixed-point 함수를 배울 준비가 끝난다. 펜실베니아 대학의 CSE121에서 나 자신이 이런 과정과 씨름할 때, 전부는 아니더라도 대부분은 강의를 따라갈 수 없었다. 교재는 너무 어려웠다. 교수님에게 이런 과정은 부당하다는 긴 하소연 편지를 썼다. 학교의 누군가가 내 말(아니면 다른 불평자)을 들은 것이 틀림없다. 왜냐하면 이 과정은 이제 자바로 진행되기 때문이다. … 차라리 이런 불평을 듣지 않았으면 좋았을 것이다. … 이제 전공과목에서 4.0을 받느라 머리를 쓸 필요가 없어진 것이다.”

아마존의 서평은 책의 내용이 좋다('great'와 'excellent' 정도의 표현은 흔하다)는 평으로 도배되어 있다. 책의 내용이 지나치게 어렵다는 것을 불평하면서도 그렇다. 사람들이 지적하는 불만 사항은 현실적인 면에 관한 것이다. 이 책은 실전에는 바로 도움이 되지 않는다. 서평 목록 처음에 나오는 피터 노빅(구글의 검색엔진 품질 책임자로 norvig.com에 가면 리스프에 대한 많은 글들을 볼 수 있다)이나 폴 그레이엄(비아웹의 창업자로 '해커와 화가'라는 책을 썼다. www.paulgraham.com에 가면 역시 리스프에 대한 많은 글이 있다) 같은 사람들은 SICP에 대해 극찬 일색이다. 두 사람은 리스프의 중요한 옹호자이고 리스프 세계에서 SICP는 중요한 교과서다. 두 사람 모두 리스프에 대해 중요한 책들을 출판했지만 SICP는 아주 중요한 책으로 평가된다.

SICP의 문화 코드, 그리고 리스프

사람들이 이렇게 생각한다면 SICP는 나름대로 중요한 의미를 지닌다. 이유는 간단하다. 사람들이 중요하다고 생각하는 그 무엇이 있기 때문이다. 책에는 생각할 내용이 많은 것이다. 고전으로 평가 받는 이유는 책이 담고 있는 내용도 있지만 책을 주제로 담론을 전개할 수 있기 때문이기도 하다. 그렇다면 책이 어려워도 고생해가며 읽을 가치는 충분하다고 볼 수 있다. 물론 아닐 수도 있다.

SICP는 한글판으로도 출판된다. 필자도 부분적으로나마 번역 과정에 참여했다. 한글 번역의 문제점과 장점을 다 같이 갖고 있는 SICP의 한글판은 컴퓨터의 고전이 번역되는 것으로 볼 수 있고 중요한 의미를 갖는다. 아무래도 한글판이 나오면 한 명이라도 더 보게 되어 있다. 이를테면 예전에 Computer Organization and Design 같은 고전이 번역되자 사람들이 더 많이 읽고 더 많은 과정에서 교재로 도입했다.
그러나 SICP를 교재로 사용하고 있는 과정은 아무래도 줄고 있다. 조엘이 말한 것과 같은 맥락이다. 그러나 컴퓨터의 중요한 고전을 독학으로 공부하는 것도 가능하다. 이미 학부를 졸업한 사람들이나 관련이 없는 학과를 나온 경우에는 독학 이외에는 방법이 없다(필자 역시 독학 내지 흥미로 공부하고 이 글을 쓰고 있다).

SICP가 쉽다거나 어렵다거나 하는 문제는 교사와 학생의 문제일 수도 있으며(예상보다 높은 수준의 교사가 필요할 것이라는 것이 개인적 의견이다) 리스프나 스킴 자체의 문제일 수도 있다. 커리큘럼이 너무 어렵고 격렬하다고 하여 HTDP(How to Design Programs)와 같은 교과 과정도 있다. 그러나 분명히 이런 격렬함이 이 책을 다른 책과 다르게 만든 그 무엇이기도 하다. 이상한 주입 과정과 사고 과정을 거치면서 분명히 어떤 변화가 나타난다. 그러나 우수한 선생이나 대가에게 배울 수 없다면 우수한 학생 또는 대가학생이라는 방법도 가능하다. 학생이 목표를 선정하고 이리저리 공부하는 방법을 고안하면 된다. 실패율은 높지만 배우는 것도 많다. 아무튼 리스프나 SICP를 배우고 이해하거나 짜보고 싶은 프로그램들이 있었으므로 해봐야 할 과정이었다.

필자는 이 책을 독학하기 위해 여러 가지 자료를 살펴보아야 했고 약간의 시간을 낼 수 있어서 여러 가지를 구경할 수 있었다. 그래서 이번에 쓰는 글은 아마추어 해커의 관점에서 해커 사상의 원류라고 할 수 있는 리스프와 리스프의 중요한 파생 언어 중 하나인 스킴을 살펴보는 것이다.
필자는 컴퓨터로 먹고 살지 않는다. 진지하기는 하지만 생업은 아니다. 아마추어다. 덕분에 하고 싶은 것들을 하고 있어도 누가 뭐라고 하지 않는다. 적극적으로 보자면 컴퓨터는 필자에게 중요한 문화 탐험의 하나다. 그래서 도대체 SICP라는 책을 만들기 위한 문화코드와 재료가 무엇인지, 그리고 역사(history)와 사람들의 이야기(biography)가 어떤 것인지가 더 중요하다. 이런 날줄과 씨줄로 리스프의 문화 코드가 만들어진 것이기 때문이다. 그래서 필자의 이야기는 완전한 전문가의 이야기도 아니며 그저 진지한 아마추어의 이야기 정도로 파악해주면 좋을 것이다.
그래서 SICP라는 책을 해설하는 것이 아니라 SICP를 만든 자료들과 근거들이 어떠한 맥락에서 어떤 경로를 거쳐 발전해 왔는가를 보는 것이 필자의 접근법이다(이러한 접근법은 시간이 조금 더 든다).

SICP의 그 이전에 리스프라는 더 거대한 덩어리가 있었다. 여기에도 문서들이 보존되어 있다. 필자는 코드만 보고 '아하!' 하고 모든 것을 이해하는 천재가 아니기 때문에 이것저것을 살펴보아야 하고 문서가 있으면 다 이해하지는 못하더라도 읽어보려고 했다. 때로는 코드만 보는 것보다는 더 이해가 빠를 수도 있겠다. 자칫하면 재미가 없을 수도 있으므로 접근방법을 미리 설명하는 것이다. 그러니까 필자의 글은 어려운 SICP를 이해하기 위한 주변 자료들을 제시하고 나름대로 설명해 보고 싶은 것이다. 실제로 리스프나 스킴이 오랜 세월 동안 진화해 왔기 때문에 역사성을 무시하지 못한다. 그래서 역사적 자료와 문헌들을 사람들의 이야기와 몇 줄의 코드에 섞어서 이야기할 수밖에 없다. 교양과목들처럼 말이다.

거슬러 살펴본 리스프의 탄생

SICP는 개정 과정을 몇 차례 거쳤는데 SICP는 리스프가 아니라 리스프의 방언인 스킴으로 되어 있다. 그리고 스킴을 만든 사람은 가이 스틸(Guy Steele)과 제럴드 서스만(Gerald Sussman)이다. 그 전까지의 리스프와 스킴의 차이점이라면 스킴은 칼 휴이트(Carl Hewitt)의 액터 모델(actor model)을 구현하기 위해 만들었으며 그 이전의 다른 리스프 구현의 전통을 이어받았다는 점이다.
그런 노력의 와중에서 전통적인 리스프에 대한 심각한 의문 제기가 있었고 일련의 사고 과정은 람다 페이퍼(lambda paper)라는 이름으로 나타난다. 결국 여러 편의 논문들이 나오고 SICP라는 책으로 만들어지기까지는 10년의 세월이 필요했다. 1970년대 초반부터 작업이 시작되어 1980년대 중반에야 책으로 나온 것이다.



존 매카시
그림 2. 리스프를 발명(또는 발견)했다고 하는 존 매카시

이른바 이들이 발표하는 람다 페이퍼라는 것을 사람들은 좋아하기도 했고 싫어하기도 했다(글들은 http://library.readscheme.org/page1.html에 있다). 그 중 "The Art of the Interpreter of, the Modularity Complex(Parts Zero, One, and Two)"라는 유명한 문서가 많은 사람들에게 영향을 주었다. 그 외에도 "Lambda: The Ultimate Imperative"와 “Lambda: The Ultimate Declarative”, 그리고 “Debunking the 'Expensive Procedure Call' Myth, or, Procedure Call Implementations Considered Harmful, or, Lambda: The Ultimate GOTO”라는 글들도 유명하지만 사람들은 이 글들을 별로 좋아하지 않았던 것 같다. "Lambda: The Ultimate X” and “X considered Harmful"이라고 풍자하는 글들도 있었다고 한다.

중요한 내용이라 언급하지 않을 수 없는 액터 모델에 대해서도 설명하면 좋겠지만 지면상 불가능하다. 일단 위키 백과의 소개 글 정도면 큰 그림을 이해하는 데는 충분할 것이다. 휴이트와 대화하면서 람다가 액터와 같다는 것을 확인한 서스만은 정말로 좋아했다고 한다. 나중에 앨런 케이(Alan Kay)와 휴이트가 만나면서 스몰토크(smalltalk) OOP(Object-Oriented Programming)의 메시지 모델과 액터 모델은 서로 많은 영향을 주고받았다.

1970년대 스킴이 람다 페이퍼를 중심으로 사람들의 관심과 비난을 한데 얻던 시절, 서스만과 함께 스킴에 대한 연구를 진행하던 가이 스틸은 당시를 아주 재미있던 시절이라고 나중에 회고했다. 스틸은 당시 대학원을 다녔다. 석사 과정에 다니는 학생이 젊은 교수와 함께 언어의 중요한 틀을 만든 것이다. 스틸은 나중에 스킴 컴파일러에 대한 논문을 쓰고 D. Hillis의 Thinking Machine으로 자리를 옮겼기 때문에 SICP가 출판될 때는 동료인 Harold Abelson이 공동 저자로 되어 있다(가이 스틸은 현재 썬(Sun)의 연구진으로 있다).
기존의 리스프에 대해 문제점을 제기한 가이 스틸은 나중에 CLTL(Common Lisp The Language)라는 리스프 드래프트의 작성자가 되었다. 드래프트를 만들며 리스프의 많은 구현들의 장단점을 취합했다. 그만큼 실력이 있었다(스틸은 C 표준안과 자바 표준 그리고 포트란의 표준안을 작성했거나 위원회의 주요 멤버이기도 했다).

스킴이 그전까지의 리스프와 중요한 차이를 보인 것은 람다에 대한 중요성을 부각시키고 람다의 행동에 대한 엄밀한 분석을 이룬 것이다. 테일 리커전(tail recursion)이나 렉시컬 스코프(lexical scope)와 같은 것도 중요한 차이점이다. 람다에 대해 생각한 것은 앞의 오리지널 람다 페이퍼라는 문서들이 바로 그 증거이며 SICP에는 이 문서들의 내용이 녹아 들어있다. 진지한 독자들이라면 호기심으로라도 람다 페이퍼들을 살펴볼 필요는 충분히 있겠다.

튜링 머신과 람다 계산법

컴퓨터 역사에서 리스프 초기 해커들은 1세대 해커에 속한다. 바로 스티븐 레비의 “해커”에 나오는 사람들이다. SICP의 저자인 제랄드 서스만 역시 1960년대 중반에 이 문화권 속에 들어와 있었다. 스티브 러셀(Steve Russell)이나 다른 해커들과 같이 구현된 지 얼마 되지 않은 리스프와 PDP 컴퓨터를 가지고 기계들과 하나가 되어 생활했다. 이들에게 있어서 리스프와 MIT의 AI 연구소는 하나의 도약대였다. 그리고 해커 문화를 탄생시켰다. AI 연구소는 자유롭게 프로그래밍을 할 수 있는 장비와 분위기를 제공한 최초의 장소였기 때문이다. 그래서 컴퓨터의 역사에서 리스프의 위치는 매우 중요하다("A Marriage of Convenience: The Founding of the MIT Artificial Intelligence Laboratory")라는 문서가 있다).

리스프가 하나의 중요한 언어가 될 수 있었던 것은 수학적인 아이디어의 표현에서 뛰어났기 때문이다. 그것은 우선적으로 람다와 리커전이었다. 시작은 조금 묘하며 컴퓨터의 시작에도 관련이 있다.

조금 더 역사를 거슬러 올라가면 리스프라는 언어를 만든 매카시가 알론조 처치(Alonzo Church)의 제자였다. 처치는 미국의 수학자이자 논리학자였다. 처치의 제자 중에는 뛰어난 사람이 많았다. 컴퓨터의 시작이라고도 하는 앨런 튜링(Alan Turing)도 처치의 제자였다. Stephen Cole Kleene이나 John George Kemeny도 처치의 제자다.
컴퓨터의 시작인 수학적인 문제를 기계적으로 푸는 문제는 튜링에 의해 튜링 기계로 알려져 있다. 이것은 1936년 튜링이 발표한 “On Computable Numbers, with an Application of Entscheidungs Problem”이라는 애매한 제목의 논문에서 표면으로 나오게 되었다. 튜링은 당시 중요한 수학적 문제였던 entscheidungs problem에 태클을 건 것이다. 이 문제는 수학자 데이비드 힐버트가 1928년 제시한 것이다. 적어도 이론상으로 주어진 수학적 주장이 증명 가능한 것인지 판단할 수 있는 명확한 프로시저가 있는지에 대한 문제다. 이런 문제는 튜링과 같은 사람을 위한 문제로 증명의 답은 “그렇지 않다”는 것이었다. 처치 역시 같은 결론에 도달한 논문을 1936년에 발표했다. 프로시저의 기계화에 대해 눈이 뜨인 것이다.

프로시저라는 의미를 더 명백하게 하기 위해 튜링은 LCM(Logical Computing Machine)이라고 부르는 추상적인 기계를 발명했다. LCM은(다른 사람들은 튜링 머신이라고 불렀다) 명령과 데이터를 담은 종이테이프를 갖고 있고 테이프를 따라 움직이는 헤드가 정해진 규칙에 따라 명령을 읽고 해석하며 테이프에 새로운 것을 기록할 수 있는 기계다. 이런 종류의 기계는 진술한 내용의 진위를 테스트하는 프로시저를 따라할 수 있다. 같은 시기 프린스턴 대학에는 폰노이만도 있었다.
문제를 푸는 기계에 대한 튜링의 생각은 자연스럽게 일반적인 컴퓨팅 기계를 만드는 쪽으로 흘렀다. 튜링은 “Proposal for Deveolpment in the Mathematical Division of an Automatic Computing Engine”이라는 제안서를 영국의 국립 물리학 연구소(NPL)에 제출했다. 그 후 에니악(ENIAC)이 나오고 다시 폰노이만에 의해 프로그램 가능한 전자식 디지털 계산기가 나왔다.

그러나 처치가 같은 문제에 동원한 수단은 람다 계산법(lambda calculus)이었다. 람다 계산법 자체가 계산 가능한 함수를 다루는 것이므로 그 자체를 가장 단순한 범용 컴퓨터라고 생각할 수 있고 람다 계산법이 나온 지 20여 년이 지난 후에 매카시는 람다 계산법을 새로운 컴퓨터 언어에 도입할 것을 고려했다. 튜링 머신이 컴퓨터라는 기계에 영향을 주었다면 람다 계산법은 컴퓨터 언어에 영향을 주었다고 볼 수도 있다.
매카시의 유명한 글 "Recursive Functions of Symbolic Expressions and Their Computation by Machine"은 1960년 4월에 작성되었다. 그 이전에는 몇 개의 메모들과 편지들이 남아있다. 이 글이 바로 리스프의 시작이라고 봐도 좋다.

매카시의 아이디어는 MIT의 AI 연구소에서 허망할 정도로 빨리 하나의 프로그래밍 언어로 만들어졌다. 처음에는 종이에 적던 핸드 컴파일 수준의 작업이 하나의 아이디어로 만들어지고 그 다음에는 스티브 러셀에 의해 실제로 컴퓨터 프로그램으로 만들어진 것이다. 리스프는 이렇게 갑자기 만들어진 것이다.
람다 함수를 이야기하면 독자들이 질릴 것 같아서 실제로 리스프가 어떻게 구현되었는가를 보여주는 것이 재미있을 것 같다. 실제로는 SICP 4장에 나오는 내용을 아주 간단하게 미리 설명해보자는 것이다.

그렇다면 매카시가 만들었다는 리스프라는 것이 도대체 무엇인가. 매카시가 사용했다는 IBM 704가 없으니 오늘날의 PC로 만들어 보는 수밖에 없다. 실제로 폴 그레이엄이 이런 실험을 했다. 폴 그레이엄이 책에 수록하지는 않았으나 인터넷에서 볼 수 있는 The Roots of Lisp라는 글은 매카시가 쓴 논문을 오늘날 우리가 사용하는 커먼 리스프(Common LISP)로 구현한 것이다. 그것은 바로 원시적인 인터프리터가 얼마나 쉽게 구현될 수 있는지를 보여주는 것이다. 인쇄하면 A4 한 쪽도 안 되는 소스코드로 리스프 인터프리터가 구현될 수 있다(물론 기계어로 구현하는 것은 더 복잡하지만 불가능할 것도 없다. 파이썬이나 자바로도 리스프 인터프리터를 작성할 수 있다).

원시적인 인터프리터를 만드는 것은 정말 쉽다. 여기서 조금씩 덧붙이면 SICP의 인터프리터가 된다. 메타 서큘러 인터프리터라고 하는 것으로 리스프가 수행되는 기계가 있다면 리스프를 돌려보는 인터프리터로 귀착된다. 그리고 이 코드는 빈약하기 그지없던 1960년대의 하드웨어로도 잘 수행되던 코드다. 이 간단한 코드가 코드를 만들고 그 코드가 코드를 또 만들어낸 것이다. 인공지능의 복잡한 코드들도 간단한 인터프리터에서 시작된 것이다.
이 인터프리터의 모든 식은 일곱 개의 간단한 원시 연산자로 해결할 수 있다. 리스프의 식을 리스트로 표현하면 가장 먼저 나오는 식은 연산자(operator)이며 다른 요소는 인수(arguments) 또는 피연산자(operands)라고 생각할 수 있다. 연산자로 quote, atom, eq, car, cdr, cons, cond를 사용할 수 있으면 원리적으로 리스프 인터프리터를 만들 수 있다.

   소셜 북마크

   mar.gar.in mar.gar.in
    digg Digg
    del.icio.us del.icio.us
    Slashdot Slashdot

  1. (quote x)는 x를 되돌리며 ‘x와 같다.
  2. (atom x)는 x가 아톰이라는 기본형의 원소이거나 빈 리스트이면 t를, 아니면 ()를 되돌린다(t는 참을 의미하고 ()는 거짓을 의미하는 값이라고 하자).
  3. (eq x y)는 x와 y의 값이 같으면 t를, 아니면 ()를 되돌린다.
  4. (car x)는 리스트 x의 첫 값을 되돌린다.
  5. (cdr x)는 리스트 x의 첫 값을 제외한 나머지 값을 되돌린다.
  6. (cons x y)는 x로 시작하고 리스트 y의 값들이 따라오는 리스트를 돌려준다.
  7. (cond (p1 e1) ... (pn en)은) p1부터 시작하여 p로 시작하는 식이 참이 나올 때까지 계산한다.
  8. 만약 참이 나오면 해당하는 식 e를 전체 cond의 값으로 되돌려준다.

이게 다인가? 다는 아니지만 이 연산자들만으로 인터프리터를 만들 수 있다. 다음 회에는 앞의 식들에 간단한 설명을 붙이고 진짜 인터프리터를 만들어 수행을 시켜보겠다.





신고
Trackback 0 Comment 0


티스토리 툴바