L-99
L-99とは99問あるLispの問題集のようなものらしく、私のようなビギナーには良いかもしれないと思いチャレンジしてみました。L-99のURLはこちらP01は「リストの最後の要素を返すmy-lastという関数を作る」という問題。
「むむ…
last
という関数を使えばすぐに結果が得られるような…でも問題の意図は違うところにありそうな…」ということで以下のような感じになりました。
(defun my-last (l)
(if (atom l)
nil
(if (eql (cdr l) nil)
l
(my-last (cdr l)))))
----
結果
----
* (my-last '(a b c d))
(D)
もう一つはwhen
を使ったバージョン
(defun my-last2 (l)
(when (typep l 'list)
(if (eql (cdr l) nil)
l
(my-last (cdr l)))))
前者は、まず引数の値がリストでなければならないので、atom
関数でチェックします。atom
関数は、アトムか空リスト(nil)なら真、それ以外は偽を返すので、要素のあるリストかどうかチェックできます。
* (atom 1)
T
* (atom '())
T
* (atom nil)
T
* (atom '(1))
NIL
要素のあるリストかどうかチェックした後、もしcdr
がnil
の場合、要素は1つだけということが確定するので、その値を返せばいい。そうでないなら、要素は2つ以上あるわけですから、再帰を使ってcdr
がnil
になるまで要素をチェックしていけばいい。という感じに仕上がりました。後者は、
when
を使うので、引数の型がリストの場合のみ処理を行います。when
を使った場合のほうが少しだけ速かったですが、なるべくPure Lispなもので続けてやっていきます。続いてP02。「リストの最後の2つの要素を返すmy-but-lastという関数を作る」という問題。
「むむむむ…」
先程の関数を改良してみる。
(defun my-but-last (l)
(if (atom l)
nil
(if (< (length l) 2)
nil
(if (eql (length l) 2)
l
(my-but-last (cdr l))))))
----
結果
----
* (my-but-last '(a b c d))
(C D)
cond
を使うと以下のようになりました。
(defun my-but-last2 (l)
(cond
((atom l) nil)
((< (length l) 2) nil)
((eql (length l) 2) l)
(t (my-but-last (cdr l)))))
----
結果
----
* (my-but-last2 '(a b c d))
(C D)
続いてP03。「リストのn番目の要素を返すelement-at関数を作る」という問題。
(defun element-at (l n)
(if (atom l)
nil
(if (eql n 1)
(car l)
(element-at (cdr l) (1- n))))
----
結果
----
* (element-at '(a b c d e) 3)
C
もしnが1ならば、先頭の要素のことなので、迷わずcar
。そうじゃない場合、要素は2つ以上あるので、cdr
と先頭要素1つ分を引いたnで再帰。なんだか面白くなってきました。Lispは勉強になりますね。他言語にも活かせる考え方とかがいっぱい詰まってそうです。今後も時間を作って、少しずつ問題を解いていこうかと思います。続きはこちら