Lisp을 배울 수 있는 책은 안타깝게도 구하기가 어렵다. 특히 한글로 된 책은 전무한 실정이다. 원서의 경우는 (다른 프로그래밍 언어 책과는 달리) 대부분 읽어볼 가치가 있다.
프로그래밍을 처음 배우는 사람을 위한 책으로는 David Touretzky의 Common Lisp: A Gentle Introduction To Symbolic Computation을 권할 만하다. 저자는 CMU 인문학 학생들에게 프로그래밍을 가르치기 위해 썼다고 밝히고 있는데, 그래서 그런지 많은 그림과 더불어 프로그래밍을 조금 해본 사람에게는 자칫하면 지루할 수 있다. 프로그래밍에 경험이 있는 사람은 짧은 시간 내에 읽을 수 있을 만한 책이다. 비 전공자를 위한 책이라고는 하지만, 전부 읽고 소화한다면 웬만큼
CommonLisp을 사용할 수 있게 될 것이다. 아쉽게도 CLOS, LOOP, Stream, Package 등등에 대한 언급이 없고, 매크로를 충분히 다루지 않는다. 책이 절판되었는지는 확인해보지 않았다. 도서관에서 대여해서 보기를 권한다.
프로그래밍 경험이 있는 사람에게는 Paul Graham의 ANSI Common Lisp, Sonya Keene의 Object Oriented Programming in Common Lisp, Paul Graham의 On Lisp: Advanced Techniques for Common Lisp, 그리고 Peter Norvig의 Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp 을 차례로 권한다.
Paul Graham의 첫번째 책은
CommonLisp에 대해 약간의 개념만 생기면 없어도 큰 불편이 없는 책이다. 그의 두번째 책은 내용의 거의 반 이상이
CommonLisp 매크로를 가르친다. 매크로 Wizard가 되려면 꼭 있어야 할 책이다. 아쉽게도 On Lisp은 절판된 상태인데, 다행히 그의 웹사이트에 가면
웹버젼이 있다.
Sonya Keene의 책은 CLOS - Common Lisp Object System - 를 가르치는 책인데, 아쉽게도 절판되었다. 오래 전에 "대영사"에서 수입한 적이 있었는데 혹시 모르니 전화해 보라(전화번호 바뀌었을 지도 모름). 전화는 393-0417 혹은 392-1424로, 옛날 책이라 헐값에 팔았었다. 전 세계적인 절판이기 때문에 가능하면 많이 사쟀다가 (진지하게) Lisp 프로그래밍 하는 사람을 만났을 때 선물로 주면 무지하게 좋아한다. 개인적으로 친분있는 한 Lisp 프로그래머는 이 책을 Kent Pitman이라는 Wizard급 Lisp 프로그래머에게 직접 선물 받았다고 자랑했던 기억이 난다.
Peter Norvig의 책은 이미 있는 리뷰를 참조하기 바란다.
CommonLisp을 배우려는 사람에게는 표준 스펙이 또한 필요하다. 과거에는 Guy Steel Jr.의
CLtL2(Common Lisp the Language 2nd ed.)를 사용했으나 이제는 Kent Pitman의
Common Lisp HyperSpec(CLHS) 하나면 충분하다.
대부분의 CommonLisp 프로그래머들은 CLHS를 화면 한쪽에 띄워놓고 Emacs 에디터로 프로그래밍 한다. Emacs 에디터와 브라우저를 연결시켜서 에디터에서 커서를 함수나 매크로위에 대고 키를 누르면 브라우저가 해당 CLHS 페이지를 보여주기도 한다. 필수!
웬만큼
CommonLisp에 경험이 쌓이고, CLOS가 지원하는 이상의 OOP가 필요하게 되면 또 한권의 책이 필요하다. 보통의 프로그래밍 언어에서는 지원하는 OOP에 불만이 있다고 해서 프로그래머가 그 언어 자체에 대한 프로그래밍, 즉
MetaLevelProgramming 하는 것이 불가능 하다. 하지만, CLOS는 MetaObjectProtocol(MOP)을 지원하기 때문에 자신만의 확장을 할 수 있다. 예를 들면, 관계형 DB를 OODB로 사용하고 싶을 때 이 MOP으로 Object를 자연스럽게 만들 수 있다. 바로 AspectOrientedProgramming에서 추천한 AMOP이 필요하다. 만일 Sonya Keene의 책을 구하지 못할 시에는 이책을 그 대용으로 사용해야 하는데, Lisp을 잘 모르는 상태에서는 더 큰 혼란을 초래할 수도 있으니 주의해야 한다.
위에서 말한 책들 이외에도 대부분의 Lisp관련 책들은 읽어볼 가치가 있다.
인터넷에서도 한글로 된 Lisp 관련 자료는 찾아보기 어렵다. comp.lang.lisp은 매우 활발히 토론이 이루어 지는데, 자주 Wizard급 Lisp 프로그래머들의 글을 읽어볼 수 있다. 반면 han.comp.lang.lisp은 거의 토론이 이루어지지 않고 있다. 그외 웹사이트로 Cliki, lisp.org 등이 있다.
Lisp을 처음 접할 때 올 수 있는 공포(?)를 덜기위한 팁을 몇자 적는다.
처음 Lisp을 대할 때 나타날 수 있는 생소함은 괄호에 대한 문제가 있다. 괄호는 문법을 이해하는 에디터를 사용함으로써 해결할 수 있다. Emacs 에디터를 추천한다.
CommonLisp 구현은 여러가지 있지만(
FreeSoftware로는 CMU CL이 있다) 어떤 구현을 사용하든지 Emacs에
ILisp 패키지를 이용할 것을 권한다. 이렇게 하면 나중에 다른 구현을 사용하더라도 동일한 환경을 유지할 수 있다. 단, Emacs는 Windows에서는 그다지 안정되지 않았기 때문에 시간과 노력을 아끼기 위해서 Unix계열에서만 시도하기 바란다.
괄호와 관련된 또다른 생소함은, Lisp에는 문장(statment)이 없고 수식(expression)만 존재한다는 것이다. 이런 종류의 프로그래밍 언어를 처음 대하면 대입(assignment)을 무분별하게 사용하게 되는데, 되도록 함수 위주의 프로그래밍을 연습하여 익숙해지는 것이 좋다. Lisp에서도 대입이 가능하지만 꼭 필요할 때만 사용하는 것이 바람직하다.
Lisp에서는 수식을 보통 폼(form)이라고 하는데, 폼의 첫번째로 오는 것은 연산자 역할을 하고 나머지는 인자(arguments)가 된다. 인자들은 그 자체가 폼의 형태가 될 수있는데, 최상위 폼(top-level form)이 평가(evaluate)되기 전에 모든 하위 폼들이 평가된다. 이것이 Lisp의 전형적인 폼이다. 그외에 스페셜 폼(special form)이 있는데, 이것은 앞에서 말한 평가 규칙을 따르지 않는 폼들이다. 대표적으로 if, cond, defun 등등이 있다. 모든 함수는 평범한 폼이다. 이것을 잘 기억하면, Lisp 문법은 반나절이면 다 이해하게 된다(C와 같은 프로그래밍 언어에서는 문법을 구성하는 문들이 모두 스페셜 문이라고 할수 있다!).
또 하나 함수 위주이면서 인터랙티브 환경을 갖고 있는 프로그래밍 언어를 처음 사용하는 사람이 겪게되는 어려움 중에는 출력에 대한 것이 있다. 예를 들면, Lisp 프로그래머에게
HelloWorld 프로그램을 Lisp에서 어떻게 작성하느냐 물으면 함수 하나를 달랑 던져주고 끝내기 일쑤이다.
(defun hello-world ()
"Hello World!")
즉, 문자열을 리턴하는 함수를 작성해주고 끝낸다. 사이드 이펙트(side effect) - 한글로는 무엇이죠? DeleteMe 부작용입니다. - 에 너무 많은 관심을 두지 않는 것이 좋다. 만일 처음부터 출력에만 관심이 있는 사람이라면 CLHS에서 format 함수를 참조하라. CommonLisp에서 두가지 자체 언어를 갖고 있다고 불리는 폼들이 있는데, format과 loop가 그것이다. 이 두가지를 100% 이해하고 활용하는 사람을 찾기는 쉽지않다.
Lisp을 배워서 다른 프로그래밍 언어로 프로그래밍 하는 수준이 되기까지는 그다지 오랜 시간이 걸리지 않는다(한달 혹은 두달?). Lisp 답게 프로그래밍 하기까지가 시간이 걸릴 수 있는데, 이것은 생소함, 기존에 알고 있었던 프로그래밍 언어에서 배운 불필요한 잔재, 새로운 프로그래밍 개념에 대한 충격 등등이 원인이 아닐까 생각한다.
테스트와 관련해서는 특별한 테스트 유틸리티가 없다. 그 이유는 테스트용 언어나 확장을 그다지 어렵지 않게 만들 수 있기 때문이 아닐까 생각한다. 개인적으로 회사에서는 실제로 그렇게 확장된 언어로 테스트를 작성한다. 예를들면,
(deftest "Basic Database test"
...
(test-assert (string= (name obj1) (name obj2))) ;; 이름이 같은가 체크
(ensure-exception-raised
:form (save-object obj2)) ;; 같은 이름의 객체를 저장할 때 예외가 일어나나 체크
:expected-condition duplicated-name
:assertion t
:addendum "Cannot save - duplicated name")
(test-passes))
와 같이 한다. 위의 테스트를 실행하기 위해서는 (run-all-tests), (run-test "Basic Database test"), (run-test 1) 등과 같은 인터페이스를 사용합니다(마지막 것은 테스트를 일단 수행한 후 보이는 테스트 번호를 이용한 실행으로, 테스트가 문제를 발견했을 때 프로그램을 수정하고 해당 테스트만 실행할 때 주로 씁니다).
(질문: 어떤 프로그래밍 언어에서 어떤 테스트 패키지가 가장 좋다고 알려졌나요? 한번 그 스펙을 보고 타당하다면,
SourceForge 같은 곳에서
FreeSoftware 테스트 패키지를 개발해 보는 것도 괜찮을 것 같은데...)