久々にLisp

いまだに3章までしか読めてないANSI Common Lisp.読めてないっていうか,読んでない.なんでだろう,時間はあるのに.まぁそれは置いといて,本を読んでいて出てきた,以下の3つの関数を定義してみた.

> (union '(a b c) '(c b s))
(A C B S)
> (intersection '(a b c) '(b b c))
(B C)
> (set-difference '(a b c d e) '(b e))
(A C D)

unionはor,intersectionはand,set-differenceは差ってことかな.

(defun my-union (a b)
  (if (null a)
      b
      (adjoin (car a) (my-union (cdr a) b))))

(defun my-intersection (a b)
  (if (null a)
      nil
      (if (member (car a) b)
          (cons (car a)
                (my-intersection (cdr a) b))
          (my-intersection (cdr a) b))))

(defun my-set-difference (a b)
  (if (null a)
      nil
      (if (member (car a) b)
          (my-set-difference (cdr a) b)
          (cons (car a)
                (my-set-difference (cdr a) b)))))

何時も思うけれど,Emacsのifのインデントは何でヘンテコなんだぜ?上のは整形してあるんだけれど,実際はこうなってる.

(defun my-union (a b)
  (if (null a)
      b
    (adjoin (car a) (my-union (cdr a) b))))

不満.まぁそれは置いといて,動作確認.

> (load "my-set.lsp")
;; Loading file my-set.lsp ...
;; Loaded file my-set.lsp
T
> (my-union '(a b c) '(c b s))
(A C B S)
> (my-intersection '(a b c) '(b b c))
(B C)
> (my-set-difference '(a b c d e) '(b e))
(A C D)

オッケーだね.ところで,intersectionの挙動がちょっと嫌だな.

> (intersection '(b b c) '(a b c))
(B B C)
> (my-intersection '(b b c) '(a b c))
(B B C)

uniqueじゃないというか.再帰を考えずに反復マクロとか使ってやれば簡単なんだけど*1,面倒くさいし止めておく.


ところで,まだclispでフィボナッチとか階乗とか求めてない気がするので,やっておこう.

(defun fib (n)
  (if (< n 2)
      1
      (+ (fib (- n 2)) (fib (- n 1)))))

(defun fact (n)
  (if (eql n 1)
      1
      (* n (fact (- n 1)))))
      
> (mapcar #'fib '(1 2 3 4 5 6 7 8 9 10))
(1 2 3 5 8 13 21 34 55 89)
> (mapcar #'fact '(1 2 3 4 5 6 7 8 9 10))
(1 2 6 24 120 720 5040 40320 362880 3628800)

lispって文法が単純だから,疑似コードをそのまま書けば結構すんなり動いてくれるんじゃないかって思う.実際,今回書いた全てのコードは,一発で動いたし.まぁこの程度の問題だからかな.もっと複雑になると,テストしまくらないとダメなんだろうな.

*1:memberとか使って返すリストに要素が含まれてるか見れるし