2016-03-29 10 views
0

ich neu schreiben will (ich bin nicht sicher, ob die ursprüngliche Implementierung faul von nicht ist) eine faule Implementierung von Clojure mit lazy-seq Verschachtelung, die wie folgt funktioniert:faul Neuimplementierung von Clojure Verschachtelung

(take 4 (lazy-interleave ’(1 2 3) ’(a b c))) 
(1 a 2 b) 

I mit so etwas wie das kam, aber ich bin mir nicht sicher, warum es nicht funktioniert:

(defn lazy-interleave [v1 v2] 
    (lazy-seq (concat (list (first v1) (first v2))) (lazy-interleave (next v1) (next v2))) 
    ) 

Edit:

Dank Arthur Antwort, hier ist eine modifizierte Arbeitslösung:

(defn lazy-interleave [v1 v2] 
    (lazy-seq 
     (cons (first v1) (cons (first v2) (lazy-interleave (rest v1) (rest v2)))) 
    ) 
    ) 

Antwort

3

Ein bisschen Neuformatierung zeigt das Problem:

(defn lazy-interleave [v1 v2] 
    (lazy-seq 
    (concat (list (first v1) (first v2))) 
    (lazy-interleave (next v1) (next v2)))) 

Mit anderen Worten, ich ist eine faule Sequenz erstellt, die, wenn sie realisierten , wird (concat (list (first v1) (first v2))) auswerten, das Ergebnis ignorieren und dann versuchen, (lazy-interleave (next v1) (next v2)) auszuwerten und zurückzugeben. Dieser Aufruf an lazy-interleave macht das gleiche, wieder fallen die ersten Elemente v1 und v2, und so weiter, ad infinitum.

Sie kommen nie auf den Grund, weil Sie keinen leeren Scheck haben, und so nil zurückgibt, geht es gerade weiter, nachdem Sie beide Folgen erschöpft haben. Sie erhalten keine StackOverflowError, weil Sie Lazy-Sequenzen anstelle von Rekursion verwenden.

Eine korrekte Implementierung würde wie folgt aussehen:

(defn lazy-interleave [v1 v2] 
    (when (and (seq v1) (seq v2)) 
    (lazy-cat [(first v1) (first v2)] 
       (lazy-interleave (rest v1) (rest v2))))) 
+0

Danke, ich wusste nicht, dass es eine 'faule Katze' gibt. Nur eine Frage: auch ohne 'nil' Prüfung mit Lazy-Cat können wir eine begrenzte Anzahl von Elementen aus' faul-interleave' übernehmen, aber warum können wir es nicht mit Lazy-Seq machen? In meinem Beispiel bekomme ich '(1 nil)' für '(take 2 (lazy-interleave [1] []))', aber selbst mit 'take' funktioniert mein Code nicht – Yar

+2

Als Programmierer, der Katzen mag Ich versuche, diese Funktion zu benutzen, wann immer es gemacht werden kann, um –

+0

@ArthurUlfeldt lol total zu passen es hat. Danke noch einmal. – Yar

1

interleave ist schon faul:

user> (interleave (take 5 (iterate #(do (println "sequence A:" %) (inc %)) 0)) 
        (take 5 (iterate #(do (println "sequence B:" %) (inc %)) 100))) 
sequence A: 0 
sequence B: 100 
sequence A: 1 
sequence B: 101 
sequence A: 2 
sequence B: 102 
sequence A: 3 
sequence B: 103 
(0 100 1 101 2 102 3 103 4 104) 


user> (take 4 (interleave (take 5 (iterate #(do (println "sequence A:" %) (inc %)) 0)) 
          (take 5 (iterate #(do (println "sequence B:" %) (inc %)) 100)))) 
sequence A: 0 
sequence B: 100 
(0 100 1 101) 

Und der Kern der es Implementierung sieht ähnlich wie Ihr Beispiel:

(lazy-seq 
     (let [s1 (seq c1) s2 (seq c2)] 
     (when (and s1 s2) 
      (cons (first s1) (cons (first s2) 
           (interleave (rest s1) (rest s2))))))) 

Außer es funktioniert auch auf mehr als zwei Sequenzen, so hat es eine andere Artigkeit, die han dles diesen Fall.