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
を使います。