条件式
Lispにはif式以外にも条件式があるらしいので調べてみた.
復習.if式は一つの条件式と条件式の評価値に応じて実行される二つの本体となる式がある.
> (setf x 10) 10 > (if (> x 5) (format t "x > 5~%") x) x > 5 NIL > (setf x 3) 3 > (if (> x 5) (format t "x > 5~%") x) 3本体に複数の式を記述したければ,ブロックを使用する.
> (setf x 10) 10 > (if (> x 5) (progn (format t "x = ~A~%" x) (format t "x > 5~%")) x) x = 10 x > 5 NIL > (setf x 3) 3 > (if (> x 5) (progn (format t "x = ~A~%" x) (format t "x > 5~%")) x) 3if式全体の評価値は実行された本体の式の評価値である.
when式はif式とよく似ているが,本体式を複数持つことができる(暗黙のprognでまとめられる).条件式が偽の場合は何も実行されずnilが評価値となる.
> (setf x 10) > (when (/= x 0) (format t "~A/2 = ~A~%" x (/ x 2)) (/ x 2)) 10/2 = 5 5 > (setf x 0) 0 > (when (/= x 0) (format t "~A/2 = ~A~%" x (/ x 2)) (/ x 2)) NIL条件式が真の場合のwhen式全体の評価値は最後の本体の式の評価値である.unlessはwhen式とは逆に条件式が偽の場合に本体式を評価する.先のwhen式の例はunlessを使用すると以下のようになる.
> (unless (= x 0) (format t "~A/2 = ~A~%" x (/ x 2)) (/ x 2)) 10/2 = 5 5 > (setf x 0) 0 > (unless (= x 0) (format t "~A/2 = ~A~%" x (/ x 2)) (/ x 2)) NIL条件式が偽の場合のunless式全体の評価値は最後の本体の式の評価値である.条件式が真の場合はnilである.
cond式を使用するとwhen式の入れ子を代替し,簡潔に表現できる.すなわち条件式と本体の組を複数記述することができる.
> (setf x -1) -1 > (cond ((< x 0) (format t "x < 0 ~%") x) ((= x 0) (format t "x = 0 ~%") x) ((> x 0) (format t "x > 0~%") x)) x < 0 -1 > (setf x 0) 0 > (cond ((< x 0) (format t "x < 0 ~%") x) ((= x 0) (format t "x = 0 ~%") x) ((> x 0) (format t "x > 0~%") x)) x = 0 0 > (setf x 1) 1 > (cond ((< x 0) (format t "x < 0 ~%") x) ((= x 0) (format t "x = 0 ~%") x) ((> x 0) (format t "x > 0~%") x)) x > 0 1cond式では条件式を順番に評価し,最初に真となった条件式に対応する本体式を実行する.そして最後の本体式の評価値をcond式全体の評価値とする.cond式では最後に条件式をtとしたものをいれておくとdefaultとして使用できる.これは多くの場合「行儀のよい」コードだと思う.
case式はBASHスクリプトなどのcase文やCなどのswitch文と似ている.キーリストの要素の中に第一引数と等しい値があれば,その節に対応する式(複数可)を評価する.
> (setf month 1) 1 > (case month ((2 4 6 9 11) (format t "Not 31 days~%") month) ((1 3 5 7 8 10 12) (format t "31 days~%") month)) 31 days 1 > (setf month 2) 2 > (case month ((2 4 6 9 11) (format t "Not 31 days~%") month) ((1 3 5 7 8 10 12) (format t "31 days~%") month)) Not 31 days 2case式全体の評価式は最後に評価された式の評価値である.cond式と同様,最後の節のキーリストの要素にtをいれておくとdefaultとして働く.case式ではtのかわりにotherwiseをdefaultに使用することもできる.
> (setf month 1) 1 > (case month ((4 6 9 11) (format t "30 days ~%") 30) ((1 3 5 7 8 10 12) (format t "31 days ~%") 31) (otherwise (format t "28 or 29 days ~%") nil)) 31 days 31 > (setf month 2) 2 > (case month ((4 6 9 11) (format t "30 days ~%") 30) ((1 3 5 7 8 10 12) (format t "31 days ~%") 31) (otherwise (format t "28 or 29 days ~%") nil)) > (setf month 4) 4 > (case month ((4 6 9 11) (format t "30 days ~%") 30) ((1 3 5 7 8 10 12) (format t "31 days ~%") 31) (otherwise (format t "28 or 29 days ~%") nil)) 30 days 30