2015/04/11
Wikipeaidのif文のページの下の方の「論理積・論理和による擬似的なif文」のところに、andやorでif文と同様なことができると書いてあります。
たしかに
(if (odd? x)
(println "TVの音量は偶数で!"))
は、
(and (odd? x) (println "TVの音量は偶数で!"))
と同じ動作をしますもんね(Clojureのandは、内部でifを使っているマクロですし)。
ただし、この2つのコード、戻り値は異なっているんですよ。
ifで条件が偽でelseが省略されていた時はnilで、andで最初の引数が偽だった場合は最初の引数(上の例の場合はfalse)が返ります。そしてClojureでは、nilとfalseを異なるものとして扱う場合があります。例として、私が大好きなkeep関数に登場していただきましょう。
(keep #(if (= (:programming-language %) "Clojure")
(:name %))
systems)
;; この程度だとfilterとmapで書いた方がキレイなのですけど、例なのでご容赦ください。
このコードでは、ifの代わりにandを使うことはできません。andを使うと、Clojureなシステムの場合は名前を、そうでない場合はfalseを返すという無意味な処理になってしまいますもんね。
あと、consやconcat、mapcatのようなシーケンスを作る関数では、nilを要素数がゼロのシーケンスとしてみなしてくれます。もしこれらの関数にfalseを渡したら、実行時エラーになってしまいます。
つまり、nilはfalseよりも使い勝手がいいんですよね。偽を表現する場合にも、存在していないことを表現する場合にも、空の集合を表現する場合にも使える。
だから、結果がどのような使われ方をするか分からない関数の戻り値に関係するような場合、私はifを使います。そうでない場合、結果を同じ関数内で消費するような場合は、一行で書いても違和感が少ないandを使うようにしています。これが私のコードを書くときのルールなわけですな。
#あと、どうしてもelseが必要な場合は、ifを使うしかないのでifを使っています。
そうそう。最初に挙げたTVの音量の場合はどちらにするかといえば、printlnという処理をするかどうかの判断なので、処理のための分岐であることが明確になるように、私ならwhenを使います。