debian lennyでCommon Lisp(clisp)

※実際には11/22のネタです。

■インストール

$ apt-cache search ^clisp\$
clisp - Common Lisp の実装 GNU CLISP

$ sudo apt-get install clisp

■「Hello World」
 インタプリタは面倒なので標準入力から。

$ echo '(format t "Hello World")' | clisp -q -
Hello, World

$ echo '(format t "Hello, World")' | clisp -q
[1]> Hello, World
NIL

■1から100までの数を足し算する

$ echo "(+ `seq 1 100`)" | clisp -q
[1]>
50501から1000までなら?

$ echo "(+ `seq 1 1000`)" | clisp -q
[1]>
5005001から10000までなら?

$ echo "(+ `seq 1 10000`)" | clisp -q
[1]>
50005000

■ガウス

★1から100までの場合、
 1+99,2+98,3+97...とすると、50が余るので、
 100*50+50=5050、これは以下のように書ける。

$ echo "(+ (* 100 50) 50)" | clisp -q

⇒つまり1からnまでの和は、n*n/2+n/2で解ける。

★1から100までの一般化

$ echo '(setq n 100) (+ (* n (/ n 2)) (/ n 2))' | clisp -q
[1]>
100
[2]>
50501から1000までの一般化

$ echo '(setq n 100) (+ (* n (/ n 2)) (/ n 2))' | sed s/"100"/"1000"/ | clisp -q
[1]>
1000
[2]>
500500

★以下のようにも書ける

$ num=100000;echo '(setq n '$num') (+ (* n (/ n 2)) (/ n 2))' | clisp -q
[1]>
100000
[2]>
5000050000

■黄金比

以下のページが分かりやすかった。

SICPの問題をCommon Lispで解いていく(25) 問題1.35~36

★fai.lispの準備

$ echo '(defvar tolerance 0.00001)

(defun fixed-point (f first-guess)
(labels ((close-enough-p (v1 v2)
(< (abs (- v1 v2)) tolerance))
(try (guess)
(let ((next (funcall f guess)))
(if (close-enough-p guess next)
next
(try next)))))
(try first-guess)))' > fai.lisp

★入力側を準備

$ echo '(fixed-point (lambda (x) (+ 1 (/ 1 x))) 1.0)' > fai.input

★実行する

$ cat fai.input | clisp -q -i fai.lisp
;; Loading file fai.lisp ...
;; Loaded file fai.lisp
[1]>
1.6180328

■フィボナッチ数列

 以下が分かりやすい
 http://d.hatena.ne.jp/sirocco/20100825/1282714226

★fib.lispを作成

$ echo '(defun mk-list (x max)
(if (= x max) 
(list max)
(cons x (mk-list (+ x 1) max))))

;; 二重再帰
(defun fib (x) 
(cond
((= x 1) 1)
((= x 2) 1)
(t (+ (fib (- x 1))(fib (- x 2))))))' > fib.lisp

★「'」があるので、「""」で囲うかちょっと変な方法でエスケープ「\'」する

$ echo "(mapcar #'fib (mk-list 1 10))" | clisp -q -i fib.lisp
;; Loading file fib.lisp ...
;; Loaded file fib.lisp
[1]>
(1 1 2 3 5 8 13 21 34 55)

$ echo '(mapcar #'\''fib (mk-list 1 10))' | clisp -q -i fib.lisp
;; Loading file fib.lisp ...
;; Loaded file fib.lisp
[1]>
(1 1 2 3 5 8 13 21 34 55)

★再帰はメモリを食うけど、いくつ数列を出したいか明確にしたい。

$ num=15;echo '(mapcar #'\''fib (mk-list 1 '$num'))' | clisp -q -i fib.lisp
;; Loading file fib.lisp ...
;; Loaded file fib.lisp
[1]>
(1 1 2 3 5 8 13 21 34 55 89 144 233 377 610)

■今日のまとめ
 for/whileでも足し算は出来るがlispの関数や再帰を使うと更に直感的。
 bashでも何でもshellを使うとlispインタプリタをコマンドと同等に扱えて更に楽出来る。
 「lispって簡単だよ。」という説明(のつもり)。。。w