Lisp勉強中(6) 分岐

最近仕事が終わるのが22時とか23時とかであんまり勉強が進まない。とはいえ今日は大事そうなところを覚えた。まあでも初期段階に覚えることって、大抵は大事なことだよね、言うまでもなく。

if

前回覚えた比較を使って分岐ができる。

(setq a 1)
(if (= a 1) (print "aは1です") (print "aは1じゃない"))
=>"aは1です"

(setq a 2)
(if (= a 1) (print "aは1です") (print "aは1じゃない"))
=>"aは1じゃない"

うむ。(if 条件 trueの時 falseの時) みたいに書くのか。falseの時の記述は省略してもOK(もし条件がfalseだったら何もしない)。

when

whenという書き方もある。

(setq a 1)
(when (= a 1) (print "a") (print "は") (print "1") (print "です") (print "!"))
=>"a"
=>"は"
=>"1"
=>"です"
=>"!"
=>"!"

(setq a 2)
(when (= a 1) (print "a") (print "は") (print "1") (print "です") (print "!"))
=>nil

(when 条件 trueの時 trueの時 trueの時 ...) って書く。falseの時の動作は書けないけど、trueの時の動作を複数書ける。

出力される"!"が重複するのは、printで出力した"!"と評価結果が出力された"!"があるため。

unless

unlessはwhenの逆。

(setq a 1)
(unless (= a 1) (print "a") (print "は") (print "1") (print "じゃない") (print "!"))
=>nil

(setq a 2)
(unless (= a 1) (print "a") (print "は") (print "1") (print "じゃない") (print "!"))
=>"a"
=>"は"
=>"1"
=>"じゃない"
=>"!"
=>"!"

(unless 条件 falseの時 falseの時 falseの時 ...) って書く。条件がfalseの時の動作を複数書ける。

もちろん (when (not 条件) ...) で代用できそうだけど、スッキリ書ける方unlessの方が好きかも。

cond

こんなのもある。

(setq a 1)
(cond ((= a 1) (print "aは") (print "1です") (print "!"))
      ((= a 2) (print "aは") (print "2です") (print "!"))
      ((= a 3) (print "aは") (print "3です") (print "!"))
      (t (print "aは") (print "なんだろう") (print "?")))
=>"aは" 
=>"1です" 
=>"!" 
=>"!"

(setq a 5)
(cond ((= a 1) (print "aは") (print "1です") (print "!"))
      ((= a 2) (print "aは") (print "2です") (print "!"))
      ((= a 3) (print "aは") (print "3です") (print "!"))
      (t (print "aは") (print "なんだろう") (print "?")))
=>"aは" 
=>"なんだろう" 
=>"?" 
=>"?"

これがcond。

(cond (条件1 条件1がtrueの時 条件1がtrueの時 ...)
      (条件2 条件2がtrueの時 条件2がtrueの時 ...)
      ...)

上から順に条件に合致するか調べて、合致したら条件の後ろを評価して抜ける。合致しなかったら条件の後ろは無視して次の条件を調べる。っていう感じ。複数に合致するような場合も、最初のやつしか評価されない。

最後まで合致しなかったらnilが返るらしい。ただ、上に書いたテストコードでは、最後の条件をtとしていて、必ず合致するようにしている。CやJavaのswitch文でいうdefault句みたいなことをするためにはこう書くわけか。

case

こっちの方がswitch文っぽい。

(setq a 1)
(case a
  (1 (print "aは") (print "1です") (print "!"))
  (2 (print "aは") (print "2です") (print "!"))
  (3 (print "aは") (print "3です") (print "!"))
  (otherwise (print "aは") (print "なんだろう") (print "?")))
=>"aは" 
=>"1です" 
=>"!" 
=>"!"

(setq a 5)
(case a
  (1 (print "aは") (print "1です") (print "!"))
  (2 (print "aは") (print "2です") (print "!"))
  (3 (print "aは") (print "3です") (print "!"))
  (otherwise (print "aは") (print "なんだろう") (print "?")))
=>"aは" 
=>"なんだろう" 
=>"?" 
=>"?"

otherwiseってなんか長いなあ。

使い分け

これらはうまく使い分けできそう。

  • trueのときとfalseのときでやりたいことがあるならif
  • trueのときだけでいいならwhen
  • falseのときだけでいいならunless
  • いろいろ調べたいならcond
  • ひとつの変数について色々調べたいならcase

こんな感じかな。実際にコード書いて見たらこの辺は変わってくる可能性もあるけど。