2012-02-20 4 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에 대해,이 예제는 filter의 게으름가 호출에서 오는

(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

반면 나를 이해하는 데 도움이 재귀 루프의 분기 if에서 filter. 코드가 다른 lazy-seq에 도달하여 다른 요소가 요청 될 때까지 seq을 평가하는 것을 중지합니다.

my-red을 구현하면 lazy-seq에 전화가 한 번만 울리며 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 []))))) 

기본적으로, 당신이 포장하고 (게으른-SEQ) 하나 개의 큰 RECUR 루프에서 모든 작업을 수행하는 씨 기능, 주위를.

2

모두 lazy-seq은 인수를 취하고 실행을 지연합니다. 진정한 지연 시퀀스를 생성하려면 모든 링크를 lazy-seq 호출로 감싸 야합니다. 게으름의 "입상 성"은 lazy-seq에 대한 호출간에 얼마나 많은 작업이 이루어 졌는지를 나타냅니다. 이 문제를 해결할 수있는 한 가지 방법은 lazy seq를 반환하는 상위 수준 함수를 사용하는 것입니다.

또한 꼬리 재귀와 지연은 상호 배타적입니다. 각 단계에서 재귀 호출이 지연된 seq로 래핑되고 반환되므로 스택 오버플로가 발생하지 않습니다. 그런 다음 호출자가 lazy seq를 평가하려고하면 재귀 호출이 호출되지만 시퀀스 함수 자체가 아니라 시퀀스 함수의 원래 호출자가 호출하므로 스택이 증가하지 않습니다. 이는 trampolines (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))))) 

참고 : 여기에

는 게으른 버전입니다.

관련 문제