ド素人が始めるCommon Lisp 8. 条件分岐

Common Lisp ド素人

今回も引き続き"Common Lisp: A Gentle Introduction to Symbolic Computation"を読んで自分の理解をまとめていく。

前回自分で関数を定義できるようになりました。より複雑な制御ができるように今回はConditionals、条件分岐を学んでいく。

Contents

if

どんなプログラミング言語でもたいていあると思われるif。ある条件を見たす場合の処理と満たさない場合の処理を記述する。then節、else節には一つの式しか入らない。一連の式を入れたい場合はprognを使用する。
返り値は最後に評価した式の値。

基本の形

(if test then-case else-case)   ;testが真ならばthen-caseを、偽ならばelse-caseを評価する

ifを用いた自作evenp(真偽を返してないのでpredicatesではないか。。)

(defun my-evenp (n)
  (if (zerop (mod n 2))
      "True, it's even."
      "False, it's odd."))

(my-evenp 1)    ;-> "False, it's odd."
(my-evenp 2)    ;-> "True, it's even."

真偽を返すバージョン

(defun my-evenp-2 (n)
  (if (zerop (mod n 2)) t nil))

when

上記のifのelse節が必要ない場合はifではなくwhenを使うのが良いらしい。ifとは違い暗黙のprognがある。返り値は最後に評価した式の値。条件が偽の時はNIL

基本の形

(when test then-case)

whenを用いた自作evenp

(defun my-evenp-3 (n)
  (when (zerop (mod n 2)) t))   ;else部分はない

(my-evenp-3 1)  ;=>NIL
(my-evenp-3 2)  ;=>T

unless

言葉の通りwhenの反対となる。条件を満たさないときのみ処理をする。満たすときはNILを返す。

基本の形

(unless test else-case) ; = (when (not test) then-case)

unlessを用いた自作evenp

(defun my-evenp-4 (n)
  (unless (= 1 (mod n 2)) t))   ;無理やり感

(my-evenp-4 1)  ;=>NIL
(my-evenp-4 2)  ;=>T

cond

複数の条件を順番にチェックしていき満たした場合の処理をする。返り値は最後に評価した式の値。if,else if, else if, elseのようなことができる。最後のelseのためには、そこまで来たら常に真ということでtを置いておく。これも暗黙のprognありで複数の式をthen-caseに並べることができる。

基本の形

(cond (test1 then-case)
      (test2 then-case)
      (test3 then-case)
      ...
      (t else-case))

()のつけ方にとまどう

上記の条件分岐を一度に学んだ際は()のつけ方に少しとまどった。if when unlesstestに相当する部分が一つだけだが、condはいくつでもtestを追加できるので(test then-case)が複数並ぶことになる。またたいていtestは式になることが多く(something)となって()が多くなったように感じてしまった。
よく考えてみれば、一つの条件に対応したまとまりと考えれば何も違和感はないなと思った。

and, or

普通のandorである。ただしandはtrueの場合は最後の引数を返す。orはtrueの場合は最初のnilでなかった引数を返す。
なぜandorがconditionalsのカテゴリーにいるかというと、どちらも引数の評価をすべて行うとは限らず引数の評価をしつつ結果が確定した場合はそれ以降の引数を評価しないためである。
andの場合、引数を順に評価していきnilを見つけた場合はそれ以降評価しない。orの場合は引数を順に評価していきt(nil以外)を見つけた場合はそれ以降評価しない。

基本の形

(and arg1 arg2 arg3 ... argn)
(or arg1 arg2 arg3 ... argn)

使用例

(and t t t nil) ;=> NIL
(and t t 'something t)  ;=> T
(and t t t 'something)  ;=>SOMETHING
(or nil nil t)  ;=> T
(or (= 1 2) (oddp 3) 'something)    ;=> SOMETHING

andorを意図的に条件分岐の使い方をすることは自分にとってメリットを感じないので今のところは正にand orとしての機能が欲しいときにのみ使おうと思う。それでも引数の評価は結果が確定したところまでしかされないということは覚えておこう。

まとめ

  • 条件分岐を扱う特殊形式if, when, unless, condを学んだ。
  • 読み手にわかりやすいように使い分けるのがよさそうだ。
  • and, orも引数がすべて評価されるとはかぎらないので特殊形式
  • and, or条件分岐のように使うこともできる。(おそらく自分は使わない)

余談

neovim and vlimeの環境は結構気に入っていたのだが、自分の操作もしくは自分の環境の問題だと思うが、たまに意図と異なる動きをすることがあった。それなりな頻度で起きるが再現方法、対処方法、原因等何もわからなかった。ということで環境を変えてみることにしました。今はspacemacsのcommon-lispレイヤーを使っています。

コメント

タイトルとURLをコピーしました