TL;DR

  • Clojure の再帰では、関数名の代わりに recur を使うとメモリ効率が良くなる。recur は関数内で最後に実行する式(末尾再帰)でなければならない。
  • Clojure にはデフォルト引数がないので、初期値を渡すラッパー関数を作る。

内容

次のような、カウントダウンする関数を考える。

(defn count-down [number]
  (println number)
  (if (pos? (dec number))
    (count-down (dec number))))
 
(count-down 5) ; nil
;; 5
;; 4
;; 3
;; 2
;; 1

上のように関数名を指定する代わりに、recur を使うこともできる。

(defn count-down [number]
  (println number)
  (if (pos? (dec number))
    (recur (dec number))))

recur を使うと、最適化によりメモリ効率が良くなる。また、recur は関数内で最後に実行すべき文(末尾再帰)である必要がある。

次は渡された整数のシーケンスの合計を計算する関数である。

(defn sum [numbers total]
  (if (empty? numbers)
    total
    (recur (rest numbers) (+ total (first numbers)))))
(println (sum [1 2 3 4 5] 0))

シーケンスだけを渡して合計を返す関数がほしいときは、次のようなラッパー関数を実装すればよい。Clojure には、デフォルト引数は存在しない。

(defn collection-sum [collection]
  (sum collection 0))
 
(collection-sum [1 2 3 4 5]) ; 15

キーワード