2019/07/25

LispのL-99

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
要素のあるリストかどうかチェックした後、もしcdrnilの場合、要素は1つだけということが確定するので、その値を返せばいい。そうでないなら、要素は2つ以上あるわけですから、再帰を使ってcdrnilになるまで要素をチェックしていけばいい。という感じに仕上がりました。
後者は、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は勉強になりますね。他言語にも活かせる考え方とかがいっぱい詰まってそうです。今後も時間を作って、少しずつ問題を解いていこうかと思います。続きはこちら