私はClojureの初心者ですが、私は4clojure.comの問題を試しています。そこで私はflatten
の実装を書かなければならない練習問題を見つけました。 「通常」の再帰(適切な用語があるかどうかはわからない)とは対照的に、Clojure:furの名前による再帰と再帰の比較
は、私は基本的には末尾呼び出しの最適化の概念を理解、そしてどのようにrecur
はスタックを消費しないことができます。
そして、私はここで何が起こっているかを取得しない理由です:
(defn foo1 [x]
(if (> x 0)
(do (println x)
(foo1 (dec x)))))
(defn foo2 [x]
(if (> x 0)
(do (println x)
(recur (dec x)))))
予想通りfoo1
とfoo2
の両方が機能的に同じですが、(私の場合は100000)十分な大きさのパラメータを与え、スタックオーバーフロー™はfoo1
に、foo2
は正常終了します。
は今、flatten
問題へ上:
(defn flatten1 [ls]
(mapcat
#(if (coll? %)
(flatten1 %)
(list %))
ls))
(defn flatten2 [ls]
(mapcat
#(if (coll? %)
(recur %)
(list %))
ls))
テストケース:
(flatten [1 [2] 3 [4 [5 6 [7] 8]]])
(flatten1 [1 [2] 3 [4 [5 6 [7] 8]]])
(flatten2 [1 [2] 3 [4 [5 6 [7] 8]]])
期待される結果:'(1 2 3 4 5 6 7 8)
まあ、flatten1
(それはとにかく小さな入力です)[OK]を動作します。しかし、flatten2
は無期限にハングアップします。 recur
は再帰ポイントをdefn
に設定していませんか?関数を名前で再帰させたときの違いは何ですか?プログラムを少し変更することにより
説明のおかげで、 – alepeino
この問題に対処するためには、存在していても休止状態ではあるが、[名前付きループに再帰する]という提案がある(http://dev.clojure.org/display/design/Named+ループ+ + recur-to)。 – Thumbnail