2012-02-20 17 views
4

私は怠惰を理解するのに苦労しています。Clojureの最も単純なレイジー関数

誰かが私の下の機能は怠け者ではない理由を私は理解するのに役立ちます

(defn my-red 
    ([f coll] (my-red f (first coll) (rest coll))) 
    ([f init coll] 
     (let [mr (fn [g i c d] 
      (if (empty? c) d 
     (recur g (g i (first c)) (rest c) (conj d (g i (first c))))))] 
    (lazy-seq (mr f init coll []))))) 

clojure.org/lazyに与えられたこの例では、

(defn filter 
    "Returns a lazy sequence of the items in coll for which 
    (pred item) returns true. pred must be free of side-effects." 
    [pred coll] 
    (let [step (fn [p c] 
       (when-let [s (seq c)] 
        (if (p (first s)) 
        (cons (first s) (filter p (rest s))) 
        (recur p (rest s)))))] 
    (lazy-seq (step pred coll)))) 

答えて

8

であるのに対し、filterで怠惰はへの呼び出しから来ています再帰的ループの分岐のif内のfilter。コードが別のlazy-seqにヒットし、別の要素が要求されるまでseqの評価を停止します。

my-redの実装では、lazy-seqが1回だけ呼び出されます。つまり、seqが評価されていないか、完全に評価されていることを意味します。

2

mr関数は、coll全体を再帰します。おそらくあなたの圧痕はあなたを誤解しているでしょう。

(defn my-red 
    ([f coll] (my-red f (first coll) (rest coll))) 
    ([f init coll] 
    (let [mr (fn [i c d] 
       (if (empty? c) 
        d 
        (recur (f i (first c)) 
         (rest c) 
         (conj d (f i (first c))))))] 
     (lazy-seq (mr init coll []))))) 

基本的に、あなたは一つの大きなRECURループですべての作業を行い、MR機能、周り(レイジー配列)をラップしている:正しくインデント、およびいくつかの役に立たないのパラメータを持つ関数は次のようになります削除。

2

すべてlazy-seqは、その引数をとり、その実行を延期します。真のレイジーシーケンスを生成するためには、すべてのリンクを遅延セグコールでラップする必要があります。怠惰の「細かさ」は、lazy-seqへの呼び出しの間にどのくらいの作業が行われるかです。これを回避する方法の1つは、遅延セグを返す上位レベルの関数を使用することです。

さらに、末尾の再帰と怠惰は相互に排他的です。各ステップで再帰呼び出しが遅延セグメントにラップされて返されるため、スタックオーバーフローは発生しません。呼び出し元がlazy seqを評価しようとすると、再帰呼び出しが呼び出されますが、シーケンス関数自体ではなく、シーケンス関数の元の呼び出し元によって呼び出されているため、スタックが成長しません。これは、トランポリン(Clojureのtrampoline関数を参照)を介して最適化された末尾再帰を実装するという考え方に多少似ています。 mrの各実行はすぐにlazy-seq呼び出し内からであるゼロまたは怠惰な配列、および再帰呼び出しのいずれかを返す方法

(defn my-red 
    ([f coll] (my-red f (first coll) (rest coll))) 
    ([f init coll] 
    (let [mr (fn mr [g i c] 
       (if (empty? c) 
       nil 
       (let [gi (g i (first c))] 
        (lazy-seq (cons gi (mr g gi (rest c)))))))] 
    (lazy-seq (mr f init coll))))) 

注:ここでは

は怠惰であるバージョンです。

関連する問題