2008년 10월 14일 화요일

Emacs 루비모드에서 대문자 C가 안 쳐지는 문제;

예전에 Emacs에서 Rails 코딩하기라고 올린 글이 있었는데, 이번에 루비코코아를 살펴보면서 이맥스를 사용하다보니, 대문자 C가 안쳐지는 문제를 발견했다; 해결 방법은 .emacs 파일의 다음 라인을

(define-key ruby-mode-map "C-m" 'newline-and-indent)
=>
(define-key ruby-mode-map "\C-m" 'newline-and-indent)

이와 같이 고쳐주면 된다.

2008년 9월 2일 화요일

여러가지 언어를 배운다는 것 - Why Lisp?

'실용주의 프로그래머'라는 책을 보면 한 달에 하나 정도 새로운 언어를 살펴보는 것이 도움이 된다는 얘기가 나온다. 어떻게 생각하는가? 새로운 언어를 배운다는 것은 노력은 잔뜩 들어가는 데 비해 얻는 것은 별로 없는 행동이 아닐까? 한 언어에서는 함수 정의를 위해 def를 쓰고 다른 언어에서는 defun을 쓴다는 걸 살펴보는 게 무슨 의미가 있을까?

언어를 배움으로써 무언가를 얻고 싶다면, 표기법의 차이가 아니라 개념의 차이를 살피려고 노력해야 한다. 언어를 익혀보면, 실제로 표기법의 차이를 익히는데 드는 시간은 그리 크지 않다. 대부분의 시간은 전에 알지 못하던 새로운 개념을 이해하는데 들기 마련이다. 언어는 사고를 지배한다. 극단적인 예이지만, 셋 이상의 수를 가리키는 말이 없는 언어를 쓰는 사람들은 수에 대한 개념이 극히 제한될 수 밖에 없다.

어떤 언어에는 있고 다른 언어에는 없는, 정말로 고유한 개념 같은 것이 있을까? 글쎄, 예를 들어 보자. Lisp이 다른 언어에 비해 가진 고유한 특징은 데이터와 코드의 형태가 같다는 것이다. Lisp의 자료구조 중 하나인 리스트는 코드를 표현하는 데도 쓰인다. 즉, 다음의 두 표현은 모두 리스트(데이터)이면서 코드이다.

(1 2 3 4)

(defun hello () "hello")

데이터와 코드의 형태가 같다는 것은 언어를 만드는 것과 프로그램을 짜는 것 사이의 경계가 없다는 것을 의미한다. 둘 다 기본 언어 위에 추상(abstraction)을 쌓아 올려서 우리가 표현하고자 하는 것을 쉽게 표현할 수 있게 만드는 것일 뿐이다. 예를 하나 들어 보겠다.

Erlang에서는 -compile(export_all). 옵션을 파일 위쪽에 선언하면 모듈 안의 모든 함수들이 다른 모듈에서 사용할 수 있도록 export 된다. Lisp에서는 어떤 패키지 안의 함수들을 export 하려면 다음과 같이 선언해 주어야 한다.

(export '(function1 function2 function3 ...))

Lisp에서 한 번의 선언을 통해 패키지 안의 모든 함수를 export 하는 with-export-all이라는 operator를 만들고 싶었다고 하자. with-export-all이 해야 할 일은 다음과 같다.

1. 코드 중에 defun(함수를 선언하는 symbol)으로 시작하는 코드가 있는지 살펴보고 있다면 함수 이름을 리스트에 저장한다.
2. 리스트에 저장된 함수 이름을 export 한다.

with-export-all을 사용하면 다음 예와 같이 확장(expansion)되어야 할 것이다.

(with-export-all
(defun hello ()
"hello")
(defvar *hey*)
(defun bye ()
"bye")))

=>

(PROGN
(EXPORT '(HELLO BYE))
(DEFUN HELLO () "hello")
(DEFVAR *HEY*)
(DEFUN BYE () "bye"))

위와 같이 동작하는 with-export-all의 코드는 다음과 같다.

(defmacro with-export-all (&body body)
(let ((function-list nil))
(loop for expression in body do
(if (equalp 'defun (first expression))
(push (second expression) function-list)))
(setf function-list (reverse function-list))
`(progn
(export ',function-list)
,@body)))

with-export-all은 리스트(코드)를 받아서 리스트의 각 요소가 함수를 선언하는 코드(리스트)인지 살펴보고 맞을 경우 함수 이름을 빼내서 리스트를 만든다. 그 뒤에 함수들을 export하는 부분을 추가한 코드(리스트)를 리턴한다. with-export-all이 하는 일은 코드를 받아서 살펴보고 조작한 코드를 리턴하는 것이다. 동시에 그것은 그저 리스트(데이터, 배열이나 벡터라고 봐도 무방할 수 있는)를 받아서 조작한 리스트를 리턴하는 것일 뿐이다.

다른 언어에서 비슷한 일을 하려면 코드를 받는 메써드를 만들어야 할 것이다. 하지만 다른 언어에서 코드는 데이터가 아니다. 따라서 코드를 넘기려면 데이터의 형식인 스트링으로 넘기던지 해야 할 터이지만, 위와 같은 예에서 파일의 코드 전체를 export_all이라는 메써드에 스트링으로 넘겨야 한다면 정상적인 코딩은 불가능해질 것이다. 코드 전체가 한 색깔로, indentation도 없이 표시되는 것을 보게 될 테니 말이다.

C의 매크로는 코드를 받아 코드를 리턴할 수 있다. 하지만 Lisp에서 데이터와 코드의 형태가 같다는 것은 데이터를 다루는 수준의 섬세함으로 코드를 조작할 수 있다는 말이 된다. C에서 위와 같이 코드를 살펴보고 복잡한 작업을 하는 매크로를 만드는 것드는 것은 어려운 일이다. 더구나 C의 매크로에는 결정적인 단점이 하나 있는데 매크로를 정의하는 데 사용되는 symbol의 name confliction(흔히 variable capture라고 일컬어지는 문제)을 피할 방법이 없다는 것이다.

(AOP를 사용하는 것은 위와 같은 operator를 사용하는 것과 다른데, 어떤 오퍼레이터가 적용되는지가 코드에 보이지 않기 때문이다. 예를 들어, 매크로를 사용하면 with-export-all-function, with-export-all-macro, with-export-all 등의 operator들을 만들어 상황에 따라 코드의 일부만 적절한 operator로 감싸는 것도 가능하다. 하지만 AOP를 사용해서 포인트컷을 정규식으로 표현하게 되면 그렇게 부분적이고 세밀한 적용은 불가능하거니와, 적용 여부가 명시적으로 눈에 안 보인다는 단점을 지닌다)

데이터와 코드의 형태가 같다는 것은 아직까지는 Lisp만의 고유한 특성이라고 할 수 있다. Lisp이 가진 가비지 콜렉션이나 interactive 프로그래밍 환경 등의 특성들을 다른 언어들이 가져가 도입했지만 아직까지도 데이터와 코드의 형태가 같다는 특성만은 취하질 못하고 있다. 왜일까? 이유는 나도 잘 모르겠다.

Lisp의 최고 장점으로 꼽히는 매크로의 힘과 우아함도 사실상 코드와 데이터의 형태가 같다는 데서 나오는 것이라고 할 수 있다(추가적으로 모든 operator가 리스트의 첫번째에 온다는 것이 언어가 가진 문법의 전부라는 것도 우아함을 만들어내는 요소라고 할 수 있다. 흔히 'Lisp에는 문법이 없다'라고 말해지기도 한다). Lisp의 매크로는 언어의 표현력에 가해지는 제약을 없앰으로써 프로그래머에게 무한한 자유를 부여한다.

요지는 언어마다 그 언어를 통해 배울 수 있는 고유한 개념이나 관점등이 있다는 것이다. 함수형 언어가 가진 개념들의 정수를 살펴보고 싶다면 Haskell, 병행성과 scalability에 관심이 있다면 Erlang, 객체 지향에 대해 알고 싶다면 Smalltalk 등이 좋을 것이다. 하지만 현재 익숙한 언어 외에 하나의 언어밖에 볼 시간이 없다면 Common Lisp을 볼 것을 추천한다. 그 이유는 Common Lisp이 여러 가지 개념들을 동시에 접할 수 있는 multi-paradigm 언어이기 때문이다. '모든것이 가능하다'라는 말이 Common Lisp을 가장 잘 표현해주는 말이 아닌가 생각한다. 프로그래머는 원하는 모든 것을 할 수 있다. 객체 지향 방식으로 프로그래밍 할 수도 있고, 함수형 언어의 특징을 사용할 수도 있다. 동적 타입에 의존할 수도 있고 정적으로 형을 선언해서 프로그램을 빠르게 만드는 것도 가능하다. 기본적으로 abstraction 레벨이 높아서 표현력이 뛰어난(더 적은 문장으로도 많은 내용을 표현할 수 있다면 표현력이 좋다고 할 수 있다) 반면에, goto나 비트연산, 스택을 다루는 등의 하위 레벨의 표현도 가능하다. Common Lisp을 통해서 다음과 같은 개념들을 익힐 수 있다.

  • atom, symbol, keyword parameter
    => Erlang의 atom, 루비의 symbol, Object-C의 키워드가 당연해 보이게 된다.

  • higher order function, currying, closure, memoize
    => 자바스크립트나 Erlang의 higher order function이나 closure가 쉽게 눈에 들어온다.

  • Object Oriented System, OO 개념의 메타 개념이라 할 수 있는 meta object protocol(MOP)
    => 루비의 MOP는 어린애 장난 수준으로 보이게 된다.

  • exception 개념의 메타 개념이라 할 수 있는 condition system

  • continuation
    => On Lisp을 읽는다는 가정 하에

  • 런타임과 컴파일타임의 구별이 없는 hot code deployment

  • 코드와 데이터의 동일성과 매크로
    => Lisp만의 고유한 특성으로, 가장 살펴볼만한 가치가 있는 개념이라고 생각한다.


Lisp을 보고 나서 다른 언어를 살펴보게 되면 Lisp에서 나온 개념의 하위 개념을 다루고 있는 경우가 대부분이기 때문에 이해가 매우 쉽다고 할 수 있다.

Common Lisp을 살펴보고 싶다면 Common Lisp 가이드를 참고하기 바란다.

2008년 5월 6일 화요일

Weblocks 웹 프레임워크 가이드

4월 한 달 동안은 논산 훈련소에 다녀오느라 공부도, 포스팅도 전혀 하지 못했다. 덕분에 Weblocks 코드를 보면서 파악했던 것들도 많이 까먹은 것 같다. Weblocks는 현재 리습 유저로서 선택할 수 있는 거의 유일한 웹 프레임워크라고 생각된다. 함부로 말할 수는 없겠지만 아이디어도 깔끔하고 여러모로 Rails보다도 나은 면이 많은 것 같다. 다만 여타 오픈 소스 소프트웨어와 마찬가지로 처음 접하는 사람에게 도움을 줄 만한 문서가 부족하다. 도움이 될 만한 문서가 있다고 해도 토론 그룹에 흩어져 있는 경우가 많아서 찾기도 쉽지 않다. 직접 자세하게 가이드를 써 보면 좋겠지만 아직 그럴 내공도 안 되고, 그래서 Weblocks를 이해하는데 도움이 될 만한 글들을 한데 링크해보는 것으로 그치려고 한다.

공식 매뉴얼
view에 관한 introduction

언제나 그렇지만 뭔가를 익히기 위한 제일 좋은 방법은 예를 보는 것이다.
hello world example
A simple blog example
이외에도 다운받은 코드의 cl-weblocks/examples/ 디렉토리 아래에 있는 예들을 살펴보는 것도 꽤나 도움이 된다.

파일 업로드에 관한 스레드
Lisp for the Web - Weblocks와 직접 관련있는 글은 아니지만 Weblocks가 hunchentoot와 cl-who 라이브러리에 바탕을 두고 있기 때문에 저 둘에 관련된 아티클도 도움이 될 거라 생각한다.
Weblocks에서 새로운 타입을 정의하는 것에 관한 아티클

2008년 3월 27일 목요일

적응형 소프트웨어로서의 웹 어플리케이션

다양한 브라우저에서 "동일하게 보이고 동일하게 동작하는" 웹 어플리케이션을 만들기란 쉽지 않다. 브라우저라는 환경이 너무나 다양한 탓이다. 다양한 환경을 다루는 솔루션은 단일한 환경을 다루는 솔루션에 비해 복잡해지기 마련이다.

같은 이유로 적응형 소프트웨어를 만드는 것도 어려운 일이다. 사실, "다양한 환경에서 제대로 기능하는 것"이 적응형 소프트웨어의 목표라고 할 때, 웹 어플리케이션은 브라우저라는 다양한 환경에서 제대로 동작하려고 애쓰는 적응형 소프트웨어라고도 할 수 있다.

여러 개의 솔루션을 종합해서 하나로 만든 솔루션은 복잡하기 때문에 유지보수가 어렵다. 다음 예를 보자.

#sidebar {
padding: 10px;
border: 5px solid black;
width: 230px; /* for Internet Explorer */
voice-family: “\“3\””;
voice-family: inherit;
width: 200px; /* real value */
}

html>body #sidebar {
width: 200px;
} /* for Opera */

이 코드는 인터넷 익스플로러와 오페라, 기타 브라우저에서 모두 똑같은 모양의 웹 페이지를 보여주기 위한 CSS 코드이다. 인터넷 익스플로러가 너비 값을 해석하는 방식의 차이 때문에 인터넷 익스플로러를 위한 너비값을 먼저 지정한 후, voice-family 속성을 사용해 인터넷 익스플로러가 선언이 끝난 것처럼 인식하게 하고, 그 후에 다른 브라우저를 위한 너비 값을 선언한 것이다. 하지만 오페라 브라우저도 인터넷 익스플로러처럼 voice-family 속성을 만나면 해석을 멈추기 때문에 아래 쪽에 오페라 브라우저만을 위해 추가적인 선언을 해 주었다. 이 코드는 서로 다른 브라우저 환경에서 동일한 모양을 보여준다는 목표를 달성하기 위해 일종의 CSS 트릭을 이용하고 있다. 이런 방식은 코드를 복잡하게 만들 뿐 아니라 브라우저들의 버전이 바뀌어 CSS를 해석하는 규칙이 변한다면 더 이상 유효하지 않게 된다. 하지만 CSS 기법을 담고 있는 많은 책들이 서로 다른 브라우저 문제를 해결하기 위해 이와 비슷한 트릭들에 의존하고 있다.

위 코드를 주석 없이 본다면 사실상 어떤 부분이 인터넷 익스플로러를 위한 부분이고 어떤 부분이 나머지 브라우저를 위한 부분인지, 맨 아래 오페라를 위해 삽입한 코드는 왜 들어가 있는건지, 알기가 어렵다. 하지만 각각의 CSS 코드를 분리해서 상황에 맞게 로드할 수 있다면 다음과 같이 될 것이다.

/* Internet Explorer */
#sidebar {
width: 230px;
padding: 10px;
border: 5px;
}

/* the others */
#sidebar {
width: 200px;
padding: 10px;
border: 5px;
}

이 편이 코드를 읽기는 훨씬 쉽다. 따라서 환경에 대응하는 각각의 솔루션을 분리하는 것이 복잡도를 줄이는 방법이다. 하지만 S라는 솔루션을 Sa, Sb, ... Sz 으로 분리했을 경우, 요구사항이 변하거나 다른 해결 방법을 사용하고자 하여 Sa가 Sa'으로 변경되면 Sb, ... Sz 도 같이 변경해 주어야 한다는 번거로움이 생긴다.

따라서 이상적인 방법은 Sa와 나머지 솔루션 사이의 차이를 Vab, Vac, ... Vaz로 정의한 다음, Sa만을 변경해 나가고 나머지 솔루션은 Sa에 Vab ... Vaz를 적용해 자동으로 생성하는 것이다.

이와 같은 생각을 웹 어플리케이션에 적용해보자. 하나의 브라우저에 대해서만 CSS나 자바스크립트 코드를 작성한 후 브라우저 사이의 차이를 정의한 룰을 적용해서 다른 브라우저들에 적합한 CSS와 자바스크립트 코드를 생성해내는 것이 가능할 것이다. 일단 각 브라우저에 적합한 코드들을 만들어 냈다면, 리퀘스트의 정보를 살펴보고 해당 브라우저에 맞는 코드를 로드하게 만드는 것은 쉬운 일이다.

솔루션 사이의 차이를 어떻게 기술할 수 있을까? 필요한 것은 코드에서 "관심의 대상이 되는 부분"을 정의하고 그 부분에 "규칙에 의한 변화"를 가해서 다른 솔루션을 만들어내는 것이다. AOP의 pointcut과 advice가 의도는 다를지언정 이와 비슷한 역할을 한다고 할 수 있다. 따라서 솔루션 사이의 variation을 정의하기 위해, pointcut과 advice 같은 형식을 이용할 수 있다.

이와 같은 생각을 variation-applier라는 도구로 구현해보았다. 이 도구는 CSS 파일을 대상으로 한다. 사용 방법은 기본 솔루션에 해당하는 디렉토리와, variation 룰들(IE.var opera.var 등등)이 들어 있는 디렉토리, 솔루션들이 생성될 디렉토리를 지정하고 apply를 누르면, variation 룰 당 하나씩 새로운 솔루션이 생성된다.


variation rule은 pointcut과 advice의 개념을 사용했지만 최대한 CSS 문법과 비슷하게 기술하도록 하였다. 사용 예는 다음과 같다.

/* base file */
#sidebar
{ width: 200px; margin: 0;}

case 1
/* var file */
#sidebar
{ width: ((calculate + 30px)); }
=>
/* result file */
#sidebar
{ width: 230px; margin: 0; }

case 2
/* var file */
#sidebar
{ width: ((before border 5px) (calculate * 1.1 + 10) (after padding 10px)); }
=>
/* result file */
#sidebar
{ border: 5px; width: 230px; padding: 10px; margin: 0;}

case 3
/* var file */
global
{ width: ((around border 0)) margin: ((delete)) }
=>
/* result file */
#sidebar
{ border: 0; }

기본적으로 selector가 같을 때만 variation 규칙이 적용되지만 variation의 selector를 global로 선언한 경우에는 selector에 관계없이 모두 적용된다.

variation-applier는 Common Lisp으로 작성되었으며 weblocks 웹 프레임워크 위에서 실행된다. 실행을 위해서는 Common Lisp과 weblocks를 설치하고, 소스 코드의 build-and-test.lisp 파일을 SLIME으로 로드(ctrl+c ctrl+l)한 후, SLIME에서 (variation-applier:start-variation-applier)를 치면 된다. 브라우저의 주소창에 localhost:8080 을 쳐 넣으면 입력 화면이 나타나는 것을 볼 수 있다.

Blogger에는 파일을 첨부할 수가 없기에 티스토리 블로그에 소스 코드를 올려놓았다.
소스 코드 다운로드

2008년 3월 22일 토요일

프로젝트 만들기

매번 패키지 설정을 하는 것이 귀찮아서 자동으로 폴더와 파일을 생성하는 함수를 짰다.

(make-project 'hello)
=>
./hello/
./hello/src/
./hello/test/
./hello/build-and-test.lisp
./hello/hello.asd
./hello/hello-test.asd
./hello/src/hello.lisp
./hello/test/hello-test.lisp

적당한 테스트와 소스 코드를 추가한 후 build-and-test.lisp 파일을 SLIME으로 로드(ctrl+c ctrl+l)하면 빌드 및 테스트가 이루어지고 결과가 표시된다.

아래 코드를 보면 짤린 것처럼 보이지만 긁어서 붙여보면 제대로 보인다; 후.. 블로거에서 코드 들여쓰기를 제대로 보이게 하려면 pre 태그를 쓰는 수밖에 없는데 이마저도 코드가 길어지면 짤려 보이니, 참 난감하다. 누구 블로거에서 코드 제대로 보이게 하는 방법 아시는 분 메일로 알려주시면 정말 감사하겠습니다. ^^;

(defun make-project (project-name)
(let ((name-string (string-downcase (symbol-name project-name))))
(ensure-directories-exist (make-pathname :directory (list :relative name-string)))
(ensure-directories-exist (make-pathname :directory (list :realtive name-string "src")))
(ensure-directories-exist (make-pathname :directory (list :relative name-string "test")))
(with-open-file (build-and-test (make-pathname :directory (list :relative name-string)
:name "build-and-test"
:type "lisp")
:direction :output :if-exists nil)
(format build-and-test
"(push (make-pathname :directory (pathname-directory *load-truename*)) asdf:*central-registry*)~%(require '~A-test)~%(~A-test:~A-test)~%(format t ~A)~%(quit)"
name-string name-string name-string "\"~%\""))
(with-open-file (asd (make-pathname :directory (list :relative name-string)
:name name-string
:type "asd")
:direction :output :if-exists nil)
(format asd
";;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*-~%~%(defpackage #:~A-asd~% (:use :cl :asdf))~%~%(in-package :~A-asd)~%~%(defsystem ~A~% :name \"~A\"~% :depends-on ()~% :components ((:module src :components ((:file \"~A\")))))"
name-string name-string name-string name-string name-string))
(with-open-file (test-asd (make-pathname :directory (list :relative name-string)
:name (concatenate 'string name-string "-test")
:type "asd")
:direction :output :if-exists nil)
(format test-asd
";;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*-~%~%(defpackage #:~A-test-asd~% (:use :cl :asdf))~%~%(in-package :~A-test-asd)~%~%(defsystem ~A-test~% :name \"~A-test\"~% :depends-on (\"~A\" :lisp-unit)~% :components ((:module test :components ((:file \"~A-test\")))))"
name-string name-string name-string name-string name-string name-string))
(with-open-file (main (make-pathname :directory (list :relative name-string "src")
:name name-string
:type "lisp")
:direction :output :if-exists nil)
(format main
"(defpackage #:~A~% (:use :cl))"
name-string))
(with-open-file (test-main (make-pathname :directory (list :relative name-string "test")
:name (concatenate 'string name-string "-test")
:type "lisp")
:direction :output :if-exists nil)
(format test-main
"(defpackage #:~A-test~% (:use :cl :~A :lisp-unit)~% (:export #:~A-test))~%~%(in-package :~A-test)~%~%(defun ~A-test ()~% (run-all-tests :~A-test))"
name-string name-string name-string name-string name-string name-string))))

2008년 3월 10일 월요일

MacPorts 사용법

MacPorts는 DarwinPorts의 새 이름으로 리눅스의 apt-get과 비슷하게 각종 소프트웨어의 설치를 쉽게 해 준다. MacPorts 홈페이지에서 dmg 파일을 받아 설치하면 되는데, 설치 후 port 명령이 매뉴얼대로 되지 않는다면, 경로 설정이 안 되어 있어서 그런 것이다. 홈디렉토리(~)에 .profile 파일을 만들어서 다음과 같이 경로를 추가한다.

export PATH=/opt/local/bin:/opt/local/sbin:$PATH

'port search 프로그램이름'(e.x. port search buildbot)과 같이 하면 port를 통해 설치할 수 있는 프로그램들을 찾아볼 수 있다. 원하는 프로그램 이름을 찾으면 'sudo port install buildbot'과 같이 인스톨하면 된다.

Common Lisp 가이드

사실 리습을 처음 공부하려면 막막하다. 어떤 책으로 시작해야 할지, 수 많은 구현 중에 어떤 구현을 사용해야 할지, 쓸만한 라이브러리나 웹 프레임워크는 어떤 게 있는지.. 알기가 어렵다. 국내에 도움을 얻을 만한 책도, 활발한 커뮤니티도 없다. 그래서 내 경험을 바탕으로, 매우 주관적인 가이드를 써 보고자 한다.

1. 구현(Implementation)
리습은 구현이 여러 개다. 언어 자체를 규정하는 Common Lisp ANSI specification이 있고, 그 specification에 맞게 누구나 커먼 리습을 구현할 수 있다. 많은 구현 중에 SBCL을 사용할 것을 추천한다. 오픈 소스이고, 빠르고, 멀티 스레드를 지원한다. 오픈 소스 중 그 다음으로 추천할만한 구현은 OpenMCL(현재는 Clozure CL로 이름을 바꿨다)정도이다.

2. 설치
리눅스, 맥, 윈도우즈 사용자인데 간편한 설치를 원한다면:
LispBox를 다운받아 설치하는 것이 간편한 방법이다. 윈도우즈 사용자일 경우 Clisp 버전을, 리눅스나 맥 사용자일 경우는 SBCL 버전을 다운받는 것을 추천한다. Clisp은 멀티 스레드를 지원하지 않기 때문에 웹 개발 같은 데 사용하기는 어렵지만, 학습 용도로는 아무 문제가 없다.

맥, 윈도우즈 사용자인데 IDE를 사용해 보고 싶다면:
Lispworks Personal Edition이라는 상용 IDE를 몇 가지 제약과 함께 무료로 사용할 수 있다.

맥 사용자인데 간편한 설치와 좀 더 맥 친화적인 환경을 원한다면:
ReadyLisp이 제격이다.

리눅스나 맥 사용자인데 일일이 직접 설치하기를 원한다면:
리습 작업환경은 사실 Emacs + 리습 구현 + SLIME 이라는 세 가지를 설치한 후 연동해 주는 것이다. Emacs와 리습 구현 자체는 apt-get이나 MacPorts를 통해 쉽게 설치할 수 있을 것이고, SLIME은 내려받아 압축을 푼 뒤 별도의 설치 없이 연동만 하면 된다. 설치방법은 리눅스나 맥이나 거의 동일하다. 다음 글들을 참조하면 된다.
http://onlisp.blogspot.com/2007/12/common-lisp-emacs_12.html
http://onlisp.blogspot.com/2008/01/sbcl-thread.html

3. 에디터
Emacs. 사실 vi나 이클립스를 사용하는 방법도 존재하긴 하지만, 리습의 에디터로는 Emacs가 거의 절대적이라고 생각해도 무방하다.

4. 책
속성으로 아주 기본적인 내용만 빠르게 흝고 싶다면:
http://onlisp.blogspot.com/2007/12/2-ansi-common-lisp.html
http://www.cs.gmu.edu/~sean/lisp/LispTutorial.html
http://psg.com/~dlamkins/sl/chapter03.html

사실 위의 내용만 봐서는 리습을 다른 언어와 차별화하는 특성이 어떤 것인지 알기 어렵다. 리습을 제대로 공부해 보고 싶다면 다음의 책들을 추천한다:

ANSI Common Lisp - Paul Graham
간명하고 재미있게 씌어진 책이다. 다만 온라인에 공개되어 있지 않다는 단점이 있다. 구할 수만 있다면 시작하기에 제일 좋은 책이긴 하다. 일부 챕터의 번역이 인터넷에 올라와 있다.

Chapter 1~4
http://xeraph.com/ => Article/프로그래밍 언어

Chapter 2, 10
http://onlisp.blogspot.com/2007/12/2-ansi-common-lisp.html
http://onlisp.blogspot.com/2007/12/10-ansi-common-lisp.html

Practical Common Lisp
매우 친절하고 자세하게 기술되어 있는 책이다. 온라인에 모두 공개되어 있다는 점도 좋다. 현 시점에서는 가장 추천할만한 책이 아닌가 생각된다. 다만, 저자가 뭐든지 늘여쓰는 경향이 있고, 책 분량이 꽤 되기 때문에 보다가 포기할 가능성도 있다.

Successful Lisp
역시 온라인에서 모두 볼 수 있다. 내용이 그리 많지 않아서 금방금방 볼 수 있고, 유용한 팁들도 꽤 있다.

On Lisp
리습이 가진 최고의 장점이라고 할 수 있는 매크로의 모든 것을 다룬 책이다. 링크한 홈페이지에서 무료로 다운받을 수 있다. 리습에 관한 기본적인 내용을 어느 정도 익혔다고 생각될 때 보는 게 좋다.

5. 커뮤니티
공부하다가 모르는 것에 대해 질문을 해야 할 필요가 있다면 구글 그룹이 좋다. Planet Lisp이라는 곳에서 리습에 관련된 글과 뉴스들을 볼 수 있다.

6. 라이브러리
대부분의 리습 라이브러리들은 Cliki라는 곳에서 찾아볼 수 있다. 다음 라이브러리들을 추천한다.
라이브러리들의 쉬운 설치를 위해: asdf
C와 C++ 라이브러리들을 가져다 쓰려면: cffi
테스팅 프레임워크: lisp-unit
웹 프레임워크: weblocks
웹 서버: hunchentoot
Database: CLSQL
정규식: cl-ppcre

7. 커먼 리습 레퍼런스
언어 자체에 대한 레퍼런스를 보고자 한다면 Common Lisp HyperSpec이 좋다(Emacs에서 slime이 로드된 상태일 때 코드 위에서 ctrl+c ctrl+d h 를 누르면 바로 해당 HyperSpec 페이지로 이동한다). 또는 CLTL2를 참고해도 좋다.