restとnextの使い分けについて
今読んでいる参考書(clojure in action)で以下の関数が例示してありました。
user=> (defn print-seq [s]
(when (seq s)
(prn (first s))
(recur (rest s))))
その本によると、この例ではseq
で明示的にシーケンスの中身の有無をチェックしているので、recur
の引数ではnext
ではなくrest
を使うべきだと書かれていました。
rest
とnext
については以下のような違いがあります。
user=> (rest [])
()
user=> (rest nil)
()
user=> (next [])
nil
user=> (next nil)
nil
見ての通り、rest
であれば引数のシーケンスが空だろうとnil
だろうと空リストを返すという違いがあります。
一方、seq
は引数でnil
を受け取っても結局nil
を返します。
user=> (seq [])
nil
user=> (seq nil)
nil
ここまで理解してみて、少し困ったことになりました。
ここまでの理解をそのままつなげると、上記の例では、関数の引数はnil
であろうとシーケンスであろうと、どちらでも構わないように思われます。つまりrest
をrecur
の引数として積極的に推奨するほどの理由が分かりません。
user=> (print-seq nil)
nil
user=> (print-seq [])
nil
user=> (print-seq [1 2])
1
2
nil
ためしにnext
版も作ってみました。
user=> (defn print-seq2 [s]
(when (seq s)
(prn (first s))
(recur (next s))))
#'user/print-seq2
user=> (print-seq2 [])
nil
user=> (print-seq2 nil)
nil
user=> (print-seq2 [1 2])
1
2
nil
実質的に何も動作に変わりがないように思われます。
例が良くないだけではないかという気もしているのですが、わざわざ「next
よりもrest
を使いなさい」と識者が書いているくらいなのだからそれには理由があるのだと思います。
だったらその人に聞けば良いではないかと言われそうで恐縮ですが、もし一般的にこのアドバイスが当てはまるパターンがあるとしたら、それはどのような場面においてなのでしょうか?あるいは慣習的なルールがあるのでしょうか?もしそういうのがあれば教えてください。
clojureはバージョン1.8です。