8

「純粋な再帰」はここでは作り上げられた用語です、ご容赦ください。

これは、2つの異なる再帰アプローチを使用した2つの例です。相互に使用するためのガイドラインは何ですか?

(defn take-while
  "Returns a lazy sequence of successive items from coll while
  (pred item) returns true. pred must be free of side-effects."
  {:added "1.0"
   :static true}
  [pred coll]
  (lazy-seq
   (when-let [s (seq coll)]
       (when (pred (first s))
         (cons (first s) (take-while pred (rest s)))))))

(defn take-last
  "Returns a seq of the last n items in coll.  Depending on the type
  of coll may be no better than linear time.  For vectors, see also subvec."
  {:added "1.1"
   :static true}
  [n coll]
  (loop [s (seq coll), lead (seq (drop n coll))]
    (if lead
      (recur (next s) (next lead))
      s)))
4

3 に答える 3

9

考慮すべきいくつかの要因:

  • loop / recurはスタックスペースを消費しないので、深くネストされた再帰を実行する場合は正しい選択です。StackOverflowError
  • loop / recurはより高速です-これはClojureで最も効率的な構造の1つであり、正しく実行されると、Javaコードの同等のforループの速度と一致するはずです。
  • 通常の再帰はより慣用的です-平均して、より明確でより機能的なコードを提供する傾向がありますが、ループ/再帰は命令型の反復スタイルに向かってよりプッシュする傾向があります
  • ループ/再帰にはさらに多くの制限があります-テール位置でのみ再帰できる、2つの異なる関数間で相互再帰を実行できないなど。ループ/再帰を機能させることができない場合もあれば、必要な場合もあります。そうするためにあなたのコードをゆがめなさい。
于 2013-01-11T06:04:01.520 に答える
2

lazy-seq/メカニズムを使用する唯一の理由は、lazy-consレイジーシーケンスを生成することです。それらが必要ない場合は、間違いなくloop/を使用する必要があります。recur

于 2013-01-11T07:23:46.447 に答える
1

そもそも関数を書くときは、単純な再帰を使用してください。次に、可能であれば、これを変更して、すべてが機能するようになったら繰り返します。

TCOの問題の1つは、再帰を無効にすると、無限の外観が得られることです。これがないと、コードはスタックオーバーフローでうまくクラッシュします。これは、必要なことです。私が最初にそれについて聞いたとき、私は再発の考えが好きではありませんでした-ほとんどの最適化はちょうど起こるべきです-しかしそれをオフに切り替えることができることは素晴らしいです。

于 2013-01-11T10:16:02.760 に答える