Common Lisp (SBCL) on Windows 7

Language/Common LISP 2011. 10. 14. 12:26 Posted by 알 수 없는 사용자
Common Lisp를 사용하기에 최적의 환경은 역시 리눅스. 최근 우분투가 참 많이 좋아졌고 많은 프로그램들이 리눅스를 지원하니 사용에 심각한 불편함은 없으나 역시 대한민국에서는 윈도우가 편하다.

윈도우 환경에서 리스프를 즐기기 위해서 clojure를 써보는 방법도 있지만 common lisp는 아니기 때문에 좀 애매하다. 돈을 주고 쓸 수 있는 것들은 윈도우용을 제공하지만 무료로 사용할 수 있는 것들 중 쓸만한 것인 clisp나 sbcl은 아직 공식적인 윈도우 버전을 제공하지 않는다. 뭐, 아직 공부 단계이니 돈 주고 사기는 아깝고, 원래 쓰던 sbcl을 사용하기로 했다.

sbcl은 아직까지는 윈도우 환경에서 "Available and Supported" 단계가 아니다. 포팅 중으로 표시되어 있다. 그럼에도 불구하고 설치는 간편하게 할 수 있도록 설치 파일을 제공한다. 인터넷 상의 여러 글에서, 아직은 불안정하다는 이야기를 많이 봤지만 얼마나 불안정한가는 더 사용해봐야 알 수 있겠다. 개인적으로는 간단한 코드를 돌려보는 수준이기 때문에 특별한 버그를 만나진 못했다.

우선 emacs windows 버전은 여기서 다운로드 받을 수 있다. 가장 최근의 bin 버전을 받는 것이 좋다. emacs는 설치파일을 제공하지는 않으며, zip으로 압축되어 있다. 받은 후에는 bin 폴더에 있는 바이너리를 직접 실행하여 사용하면 된다.

SLIME은 이 곳에서 받을 수 있으며 cvs snapshot을 받을 수 있다. SLIME을 다운 받은 후에는 최대한 path 설정이 간편한 곳에 두는 것이 좋다.

SBCL은 여기에서 받을 수 있다. windows 용을 클릭하여 다운로드 후 실행하면 설치된다. 설치할 때 주의할 점은 역시 설치될 경로 설정이다. 최대한 단순하게 하자.

경로를 단순하게 해야 하는 이유는 후에 emacs에서 경로를 설정할 때 공백이 들어간 경로나 긴 이름의 경로를 잘 해석하지 못하는 경우가 발생하기 때문이다.

리눅스에서는 홈 디렉토리에 .emacs에 설정 파일을 두면 되지만 윈도우의 경우에는 어디에 .emacs가 위치할까? 이것을 알 수 있는 간단한 방법은, 이멕스를 실행한 후 Options에서 아무 옵션이나 변경한 후 Save Options를 하면 어느 파일에 저장했는지가 아래 미니 버퍼에 나온다. 보통은 자신의 홈 디렉토리의 AppData/Roaming/.emacs 에 위치한다. 예를 들면 C:/Users/kju/AppData/Roaming/.emacs

.emacs의 위치를 찾았으니 이 파일을 수정하면 된다. 여기에 추가할 코드는 다음과 같다.
(setq inferior-lisp-program ""C:/Users/kju/SBCL/sbcl.exe")
(add-to-list 'load-path "C:/Users/kju/slime-2011-10-13")
(require 'slime)
(slime-setup '(slime-repl))
SBCL과 SLIME의 위치를 지정하는 것이다. 경로가 간단하면 좋은 이유가 여기에 있다. 그리고 경로에 공백이 있을 경우 실행되지 않는 경우가 많다. 경로를 설정할 때 한 가지 주의할 점은 폴더 구분자를 \이 아니라 /를 사용해야 한다는 점이다. 역슬래시를 사용할 경우 escape 문자로 인식하여 오류가 발생한다.

설정 후 M-x slime 해보고 REPL이 정상적으로 실행되면 끝.

ps. 리스프 코딩을 할 때 괄호가 조금 연하게 출력되면 소스코드를 보기에 편하다.
(defface paren-face
  '((((class color) (background dark))
     (:foreground "grey30"))
    (((class color) (background light))
     (:foreground "grey60")))
  "Face used to dim parentheses.")
(add-hook 'emacs-lisp-mode-hook
       (lambda ()
         (font-lock-add-keywords nil
                     '(("(\\|)" . 'paren-face)))))
(add-hook 'slime-mode-hook
       (lambda ()
         (font-lock-add-keywords nil
                     '(("(\\|)" . 'paren-face)))))
를 .emacs에 추가해서 괄호를 연한 회색으로 만들 수 있다. grey뒤의 숫자를 조정하여 입맛에 맞게 설정하자.

Common Lisp는 Unicode를 처리할 수 있을까?

Language/Common LISP 2011. 10. 14. 12:02 Posted by 알 수 없는 사용자
리스프 관련 책을 읽다가 문자열에 대한 이야기가 나왔다. 문득, 리스프가 유니코드를 처리할 수 있을까 하는 의문이 들었다. 그리고 몇 가지 실험을 해보니 전혀 한글을 해석하지 못한다는 것을 알게 되었다.

하지만 분명 설정의 문제이리라.

"SBCL unicode"로 구글링을 해보니 SBCL은 이미 유니코드에 대한 지원을 하고 있다는 것을 알 수 있었다. 컴파일 때 옵션을 줄 수 있고 하는데 나는 우분투에서 패키지로 깔았으니 옵션을 켜고 컴파일 한 것인지 아닌지 알 수가 없다. 그냥 실험을 해보면 알게 되겠지.

모든 정보는 이 곳에서 얻었다. 결론은 간단하다. 우선 emacs가 기본적으로 유니코드(UTF-8)를 사용하게 하고, SLIME도 유니코드를 사용하게 설정하면 된다는 것.

Emacs의 메뉴바에서
Options -> MULE(Multilingual Environment) -> Set Language Environment -> UTF-8을 선택하고,
Options -> Save Options를 선택해서 저장
이렇게 하면 .emacs의 custom-set-variables에 '(current-language-environment "UTF-8")라는 것이 자동 추가된다. 이멕스의 언어 환경을 UTF-8로 바꿔주는 것이다.

다음으로 SLIME을 설정해야 하는데, .emacs에 다음 한 줄만 추가해주면 된다.
(setq slime-net-coding-system 'utf-8-unix)
이멕스를 다시 실행시켜 환경 변수가 적용되게 한 후, SLIME을 띄우자.
CL-USER> #\한
#\UD55C

CL-USER> "한글"
"한글"
오. 한글을 인식한다.
CL-USER> (char-code #\한)
54620
'한'이라는 글자에 대한 코드를 얻어낼 수 있다.
CL-USER> (code-char 54620)
#\UD55C
역으로 글자로 변환. 이렇게 character code를 보면 재미가 없으니 확실히 확인해보자.
CL-USER> (coerce '(#\UD55C) 'string)
"한"
모든 것이 잘 동작한다. 그렇다면 함수 이름으로 활용해보자.
CL-USER> (defun 안녕 ()
       (format t "안녕하세요.~%"))
안녕
CL-USER> (안녕)
안녕하세요.
NIL
완벽하다.

ps. CLISP를 가지고 실험해보니 CLISP에서도 모두 잘 동작한다.

Common Lisp에서 패키지 다시 컴파일하기.

Language/Common LISP 2011. 10. 14. 11:58 Posted by 알 수 없는 사용자
아. 리스프는 정말 쉽지가 않다. 언어 자체는 너무 마음에 들지만 패키지를 사용하는 것에서 상당히 혼란스럽다. 리스프의 패키지 시스템이 나빠서라고 말하기는 힘들다. ASDF라는 좋은 시스템을 가지고 있다.

단, 문제가 되는 것처럼 보이는 건 common lisp에 대한 구현이 많다는 점이다. Lispworks, Allego CL, SBCL, CLISP, CMUCL 등등. 이들은 물론 표준을 따르고 있지만 모든 구현들이 동일하게 동작하지는 않는다. 그럴 수도 없다. 구현물마다 다른 추가 구현도 가지고 있기도 하고. 이 때문에 다른 사람의 코드를 받아서 사용하려하면 오류가 발생하는 경우가 꽤 있다. 해커들에게는 또 하나의 즐거움일 수도 있지만, 입문자인 나에겐 참 힘든 일이다.

Perl, Python 등의 알려진 언어들은 보통 가장 널리 사용되는 하나의 구현을 가지고 있다. 또한 패키지 관리 시스템도 가지고 있으니 이런 점에서는 매우 편리하다. 괜히 이런 언어들이 많이 사용되는 것이 아니라는 것을 다시 한 번 느꼈다. 많이 사용되니 그만큼 잘 되어 있는 것일 수도 있겠지만.

서론이 길었다. 오늘 여기에 남기려고 하는 팁은 패키지를 다시 컴파일 하는 방법이다. 이걸 찾아보게 된 이유는 bordeaux-threads라는 패키지 때문이다. (이름도 어렵다. 사실 '보르도'라는 지명이야 잘 알고 있지만 불어다보니 참 단어의 철자가 안 외워진다.) 이 패키지를 컴파일 하고 잘 사용하고 있었는데, 무슨 문제가 있었는지, 다른 패키지가 이 패키지를 건드린 것인지, 갑자기 함수 하나가 동작하지 않았다. bordeaux-threads:make-thread 라는 함수이다. 이 함수가 갑자기 undefined라는 것이다. 정의되어 있다고 search는 되는데 실행하면 없는 함수라니.

이 함수를 로드하면 이미 컴파일이 되어 있기 때문에 컴파일된 fasl을 로드하게 되고 문제는 반복되었다. 그렇다면 다시 컴파일 하면 해결되지 않을까 생각했다. 방법은 다음과 같다.
(asdf:operate 'asdf:load-op 'bordeaux-threads :force t)
ASDF를 이용해서 피키지를 로드하는 코드와 거의 같은 코드다. :force라는 키워드를 추가하는 것 뿐이다. 이렇게 하면 처음 패키지를 가져올 때 하는 것처럼 컴파일을 다시 하게 된다.

우분투에서 리스프 패키지 직접 설치하기

Language/Common LISP 2011. 10. 14. 11:54 Posted by 알 수 없는 사용자
이 글이 쓰여지는 현재의 환경은 SBCL, 우분투 10.04이다.

우분투의 시넵틱 패키지 관리자를 이용하면 slime이나 emacs, sbcl 등을 쉽게 설치할 수 있다. cmucl은 현재 - 왜 그러한지 모르겠지만 - 존재하지 않지만 clisp도 제공하고 있다.

우분투의 패키지 관리 시스템에서 common-lisp 관련 라이브러리들은 cl- 로 시작된다. 예를 들면 cl-md5와 같은 패키지가 있으며 이를 설치하면 /usr/share/common-lisp/ 하에 설치되어 활용할 수 있게 된다. 여기에 설치되는 패키지들은 모두 common-lisp-controller가 관리하는데, sbcl을 설치하면 자동으로 이 패키지가 설치될 것이다. 이 패키지의 기능은 어떤 lisp implementation을 사용하든 상관없이 라이브러리를 활용할 수 있도록 하기 위함이다.

sbcl에서는 (require 'package-name)을 하면 사용할 수 있고 clisp와 같은 경우에는 (clc:clc-require 'package-name)을 사용하면 된다. sbcl은 아마 clc-require를 기본으로 hook하고 있는 듯 하다.

문제는 우분투에서 모든 lisp 관련 패키지를 제공하지 않는다는 것에 있다. 누군가가 패키지를 만들어주기를 하릴없이 기다릴 수는 없는 법. 직접 패키지를 다운 받아 설치하는 수밖에. 예를 들면 cl-fad나 hunchentoot와 같은 패키지는 제공되지 않는다.

조금 의외인 것은 직접 설치하는, 이 과정이 생각외로 매우 간단하다는 것이다. SBCL을 사용하기 때문인지는 잘 모르겠으나 아직까지 동작하지 않는 패키지를 만나지 못했다. 이렇게 간단히 문제가 해결되는 이유는 이전에도 이야기한 바 있는 ASDF라는 시스템 때문이다. 대부분의 리스프 라이브러리가 ASDF를 지원하고 있기 때문에 이를 이용하면 쉽게 사용할 수 있게 된다.

방법은
  1. 필요한 라이브러리를 다운로드 한다. 대부분은 .tar.gz으로 묶여있지만 가끔은 cvs로 제공하거나 git을 사용하기도 한다. 어떤 경로든 무관하며 다운로드한 소스코드를 내가 두고 싶은 어느 디렉토리든 두면 된다. 내 경우에는 ~/asdf/ 에 모든 라이브러리 소스코드를 둔다.
  2. 홈 디렉토리에 .clc나 .sbcl이라는 디렉토리를 만든다. clc는 앞서 말한 common-lisp-controller의 약자다. 가능하면 .clc로 만드는 것이 좋을 듯 하다. 그러면 다른 lisp implementation에서도 사용할 수 있기 때문이다.
  3. (.clc로 만들었다고 가정하고) .clc내에 systems라는 디렉토리를 하나 만든다. 결론적으로 ~/.clc/systems/ 를 만드는 것. .sbcl을 만들어도 동일하다. systems라는 디렉토리를 그 안에 만든다.
  4. 이 systems/ 디렉토리 안에서 다운로드한 소스코드 중 한 파일로 심볼릭 링크를 건다. 링크를 걸 파일은 아까 풀어둔 소스코드의 .asd 파일이다. 사실 1번 과정에서 .asd 파일이 있는지 확인하는 것이 좋지만 대부분의 패키지는 .asd를 패키지 이름으로 만들어 두었기 때문에 꼭 확인하지 않아도 된다. 내 경우라면 md5 패키지를 다운로드 했을 경우, ln -s ~/asdf/md5-1.8.5/md5.asd 라고 하면 된다.
  5. 그러면 systems/ 내에 md5.asd 라는 심볼릭 링크가 생겼을 것이다. 이러면 설치가 완료된 것이다. 어떠한 컴파일 작업이나 다른 것이 필요없다. 압축을 풀고, 심볼릭 링크를 걸면 끝이다. 후에 패키지를 제거하고 싶으면 다운 받았던 패키지 디렉토리를 지워버리고 systems/ 에서 심볼릭 링크를 제거하면 된다.
  6. sbcl이 실행된 상태에서 (require 'md5) 라고 하면 첫 로드시에 알아서 패키지를 컴파일 한다. 다음부터는 컴파일 없이 바로 로드된다.
이와 같은 방법으로 어떤 패키지든 쉽게 사용할 수 있다.