Practical Common Lisp

NDA のため詳しくは書けませんが、最近 iPhone SDK に挑戦しています。まだ資料を読んでいるだけの段階ですが!何か作れたらいいなと思っています。

話は変わりますが、LISP 関連の書籍は今までに

入門Common Lisp―関数型4つの特徴とλ(ラムダ)計算

入門Common Lisp―関数型4つの特徴とλ(ラムダ)計算

On Lisp

On Lisp

の2冊購入しています。On Lisp は私にとっては難しすぎて、途中で読むのをやめてしまいました。基本的なところは 入門Common Lisp―関数型4つの特徴とλ(ラムダ)計算 で勉強したのですが、もう少し詳しい書籍が必要だと思っていました。しかし、Amazon で日本語の書籍を探してみたのですが、よさそうなものが見当たりません。最近、Appleの英語の資料を読み始め、英単語については、拙作 Wordbook2*1 で勉強しているので、洋書を読んでみようと思い立ちました。

それで

Practical Common Lisp (Books for Professionals by Professionals)

Practical Common Lisp (Books for Professionals by Professionals)

を買ってみました。購入して正解でした。

本当に丁寧に説明してあります。Optional Parameter (&optional)、Rest Parameter(&rest)、Keyword Parameter(&key) についての説明もあります。

実行環境は [id:KYoshiaki:20070225] と同じく Carbon Emacs を用いました。今回は Emacs Lisp (Elisp) ではなく Common Lisp を使う必要があります。それで書籍に紹介されている sbcl、SLIME を利用することにしました。

Leopard 以前は Fink を利用していたのですが、これを機会に MacPorts に変更することにしました。

The MacPorts Project -- Home
http://www.macports.org/
MacWiki - MacPorts
http://macwiki.sourceforge.jp/wiki/index.php/MacPorts

を参考に設定した後、パッケージ sbcl をコマンド

~ $ sudo port install sbcl

を使ってインストールしました。

また Carbon Emacs に表示されている SHA-1 の確認のために

~ $ sudo port install coreutils

を使ってパッケージ coreutils をインストールしました。
このパッケージには md5、md5sum、sha1sum などのコマンドが含まれています。ただし接頭語として g が追加されています。(gmd5、gmd5sum、gsha1sum というコマンド名になります。)

port コマンドに次の引数を渡すと、どのパッケージに含まれているか確認できます。

~ $ port provides /opt/local/bin/gsha1sum
/opt/local/bin/gsha1sum is provided by: coreutils

そして

Carbon Emacs パッケージ
http://homepage.mac.com/zenitani/emacs-j.html
Emacs をダウンロード (2008年春版; 40.8 MB)
SHA1: be4d67c6d44d937a7525fc3a8a739c443021ae29

からダウンロードしたファイル CarbonEmacs-Tiger-20080405.dmgSHA-1 を gsha1sum コマンドで求めると

~/Downloads $ gsha1sum CarbonEmacs-Tiger-20080405.dmg
be4d67c6d44d937a7525fc3a8a739c443021ae29  CarbonEmacs-Tiger-20080405.dmg

と表示されます。 私は SHA-1 が等しいか判断するためにスクリプト compare.sh

 $ cat ./compare.sh
#!/bin/sh
MD1="$1"
MD2="$2"
if [ $MD1 = $MD2 ] ; then
echo "match"
else
echo "failure"

を使っています。基本的にUnix についての知識は乏しいので、もっと良い方法があるかもしれません。

ただ単純に

Carbon Emacs パッケージ
http://homepage.mac.com/zenitani/emacs-j.html
Emacs をダウンロード (2008年春版; 40.8 MB)
SHA1: be4d67c6d44d937a7525fc3a8a739c443021ae29

に表示されている SHA-1 と gsha1sum で求めた SHA-1 をコピーして、コマンド compare.sh の引数として渡し

~ $ ./compare.sh be4d67c6d44d937a7525fc3a8a739c443021ae29  be4d67c6d44d937a7525fc3a8a739c443021ae29
match
~ $ 

match と表示されれば成功です。

SLIME については

SLIME: The Superior Lisp Interaction Mode for Emacs
http://common-lisp.net/project/slime/

から slime-2.0.zip をダウンロードしました。ファイル slime-2.0.zip を展開して作成された “slime-2.0” フォルダをホームフォルダに移動し、同封の ReadMe を参考に .emacs ファイルを

 (add-to-list 'load-path "~/slime-2.0/")  ; your SLIME directory
(setq inferior-lisp-program "/opt/local/bin/sbcl") ; your Lisp system
(require 'slime)
(slime-setup)

と設定しました。

Carbon Emacs 上で `M-x’ slime ( ESC-x slime ) と入力すると SLIME が起動します。
カーソルをファイル内の評価したい式に移動し C-c C-c と押せば実行できます。

現在、

Practical Common Lisp (Books for Professionals by Professionals)
Peter Seibel 著
CHAPTER 7 MACROS: STANDARD CONTROL CONSTRUCTS
DO

を読んでいる途中です、[id:KYoshiaki:20070225] で書いたフィボナッチ数列

F_{n}=\left\{{1 \text{ \(n=1, 2\)}\atop{F_{n-1} + F_{n-2} \text{ \(n\geq 3\)}}}\right.

もでてきます。

Practical Common Lisp (Books for Professionals by Professionals) の例

(do ((n 0 (1+ n))
(cur 0 next)
(next 1 (+ cur next)))
((= n 10) cur))

入門Common Lisp―関数型4つの特徴とλ(ラムダ)計算 の例

(defun fib (n)
(cond ((= n 1) 1)
((= n 2) 1)
(t (+ (fib (- n 1)) (fib (- n 2)))))) 

動作を説明しやすいように n = 5

(do ((n 0 (1+ n))
(cur 0 next)
(next 1 (+ cur next)))
((= n 5)
(format t "~%~d" cur)))

とします。

実行結果は

5
CL-USER> 

となります。入門Common Lisp の fib を使っても

CL-USER> (fib 5)
5

と同じ値になります。

変数の移り変わりを表で表すと

n cur next
0 0 1
1 1 1
2 1 2
3 2 3
4 3 5
5 5 8
n cur next
0 F_{0} F_{1}
1 F_{1} F_{2}
2 F_{2} F_{3}
3 F_{3} F_{4}
4 F_{4} F_{5}
5 F_{5} F_{6}

ただし F_{0} = 0 とする。

になります。

また、CHAPTER 7 の最後に出てくるフィボナッチ数列を求める関数の動作も表にしてみました。
CHAPTER 22 を読んで LOOP についてだいたい理解しましたが、finally の挙動については自信がありません。

(format t "~%~d"
(loop for i below 5
and a = 0 then b
and b = 1 then (+ b a)
finally (return a)))
i a b
0 0 1
1 1 1
2 1 2
3 2 3
4 3 5
finally 5 5 8

実行結果

5
CL-USER> 

特に for と and の違いを理解するにに苦労しました。

(loop for var = initial-value-form [ then step-form ]  ...)

for を利用する場合

(format t "~%~a"
(loop for i below 5
for x = 0 then y
for y = 1 then (+ x y)
collect y))
i x y
0 0 1
1 1 2
2 2 4
3 4 8
4 8 16

実行結果

(1 2 4 8 16)
CL-USER> 

and を利用する場合

(format t "~%~a"
(loop for i below 5
and x = 0 then y
and y = 1 then (+ x y)
collect y))
i x y
0 0 1
1 1 1
2 1 2
3 2 3
4 3 5

実行結果

(1 1 2 3 5)
CL-USER> 

*1:Wordbook2: まだ公開していません。取扱説明書を作成中です。