2

自動的に末尾呼び出しが最適化されるClojureの関数を定義する方法はありますか?

例えば

(defrecur fact [x]
    (if (= x 1)
        1
        (* x (fact (dec x)))))

内部的に次のようなものに変換されます:

(defn fact [x]
    (loop [n x f 1]
        (if (= n 1)
            f
            (recur (dec n) (* f n)))))

このようなものがすでに存在するかどうか教えていただけますか?

4

3 に答える 3

3

短い答えは「いいえ」です。

もう少し長い回答は、Clojure はテール コールの最適化が必要な場合に明示的な指示を必要とするように意図的に設計されているというものです。JVM はそれをネイティブでサポートしていないからです。

recurちなみに、なしで使用できるためloop、入力する必要はありません。たとえば、次のようになります。

(defn func [x]
  (if (= x 1000000)
    x
    (recur (inc x))))

更新、4 月 29 日:

Chris Frisz は、Dan Friedman と共にClojure TCO研究プロジェクトに取り組んでいます。現時点では誰もそれが「答え」であると主張していませんが、このプロジェクトは興味深く、有望です。Chris は最近、このプロジェクトについて非公式の講演を行い、ブログに投稿しています。

于 2012-04-18T15:43:26.110 に答える
1

私の知る限り、Clojure で末尾再帰を自動的に生成する方法はありません。

loop .. recur を使用せずに再帰を使用し、スタックをオーバーフローさせずに機能する関数の例があります。これは、これらの関数が遅延シーケンスを使用するように注意深く作成されているためです。

flatten を手書きの関数に置き換える例を次に示します。この例はhttp://yyhh.org/blog/2011/05/my-solutions-first-50-problems-4clojure-comからのものです

(fn flt [coll]
  (let [l (first coll) r (next coll)]
    (concat 
      (if (sequential? l)
        (flt l)
        [l])
      (when (sequential? r)
        (flt r)))))
于 2012-04-18T15:45:18.903 に答える
1

この決定の背後にある指針の 1 つは、特別な部分を特別に見せることでした。そうすれば、末尾呼び出しが使用されている場所と使用されていない場所が明確になります。これは意図的な設計上の決定であり、強い意見を持っている人もいますが、実際には偶像的 Clojure で recur が使用されることはめったにないので、実際には一般的な問題ではありません。

于 2012-04-18T20:32:41.633 に答える