こんにちは、たくさん寝太郎です。

やっと停電が治りました...。

住んでる地域の台風の被害が府内でも特に酷かったらしく、今でも市内では停電しているところがあるらしいです。私の家もベランダの屋根が吹き飛んだり瓦が飛んできたりと散々な有様です...。

とりあえず電気も復旧したので勉強再開します。今日はLand of Lisp第4章「条件と判断」の話です。

Common Lispでは条件式の評価において空のリストを偽として扱います。これによりリストを再帰で扱いやすくなります。

上で定義したmy-lengthは引数にリストを与えるとcdrで先頭を落とす処理を再帰的に行うことでリストの長さを返します。





条件分岐

Lispでのifの構文は次のようになっています。

( if ( 条件節 ) then else )

thenかelseの内実際に評価されるのはどちらか一方のみです。(特殊形式)

試しに次のコードを実行してみましょう。

( if ( = 0 1 ) ( / 1 0 ) ( format t "0 is not 1" ))

通常であれば、(/ 1 0)を実行しようとするとdivision errorを吐きますが上のコードでは後者のみが実行されるのでerrorは出ません。

ifの使い方の例としてランダムウォークを考えてみましょう。

( defun random-walk ( n ) ( let (( point 0 )) ( dotimes ( x n ) ( if ( = 1 ( random 2 )) ( setf point ( 1+ point )) ( setf point ( 1- point )))) ( print point )))

コインを投げて表(1)だった時は点の座標を正の方向に1ずらし、裏(0)だった時は負の方向に1ずらす試行をn回繰り返します。

( dolist ( n '( 10 100 10000 1000000 )) ( random-walk n )) 0 4 -10 52 NIL

n=10,100,10000,1000000の場合で実行すると上のように点の座標はそれぞれ0,4,-10,52となります。

(余談)

あまり処理系の話はしていませんでしたが、このコードをclispとsbclで走らせると処理速度にかなりの差が出ます。

$time clisp random_walk.lisp 0 0 -8 54 clisp random_walk.lisp 6.84s user 5.63s system 99% cpu 12.523 total $time sbcl --script random_walk.lisp 0 -6 -106 -786 sbcl --script random_walk.lisp 0.05s user 0.02s system 80% cpu 0.090 total

when, unless ( when ( 条件節 ) 式1 式2 ... ) ( unless ( 条件節 ) 式1 式2 ... ) whenは条件が真の時に、unlessは条件が偽の時に後述の式を全て実行します。





cond ( cond (( 条件節1 ) 式1 ... ) (( 条件節2 ) 式2... ) ... ( t 式 )) condフォームの条件は上から順に検査され、最初に条件を満たしたものの式を実行します。最後の条件をtとすることで他の全ての条件が満たされない時もコードが実行されることを保証します。





case ( case key ( key_list1 式1 ... ) ( key_list2 式1 ... ) ... ( otherwise 式1 ... )) caseフォームは最初にkeyを受け取り、eqlコマンドでkey_listとの比較を行い等しい要素を見つけた場合にその節の式を実行します。condと同様、最後の条件にはotherwise(tでも可)を入れておきます。



