2014-10-27 8 views
7

Hier ist eine Frage des Anfängers: Gibt es in Clojure eine Art und Weise faul, um eine beliebige Anzahl von Sequenzen zu verketten? Ich weiß, dass es lazy-cat Makros gibt, aber ich kann nicht an die richtige Anwendung für eine beliebige Anzahl von Sequenzen denken.Faule Verkettung von Sequenz in Clojure

My Anwendungsfall ist verzögertes Laden von Daten aus einer API über paginiert (offseted/Limited) Anfragen. Jede Anfrage ausgeführt über request-fn ruft unter 100 Ergebnisse:

(map request-fn (iterate (partial + 100) 0)) 

Wenn es keine weiteren Ergebnisse sind, request-fn gibt eine leere Sequenz. Dies ist, wenn ich die Wiederholung stoppen:

(take-while seq (map request-fn (iterate (partial + 100) 0))) 

Zum Beispiel könnte die API 500 Ergebnisse angezeigt und kann als spotten:

(defn request-fn [offset] (when (< offset 500) (list offset))) 

Wenn ich die Ergebnisse verketten möchten, kann ich (apply concat results) aber das wertet gespannt auf die Ergebnisse Reihenfolge:

(apply concat (take-while seq (map request-fn (iterate (partial + 100) 0)))) 

gibt es eine Möglichkeit, wie die Ergebnisse Sequenz träge verketten, sonst entweder lazy-cat oder etwas mit?

+0

Das ['lazy-cat' * Makro *] (http://grimoire.arrdem.com/1.6. 0/clojure.core/lazy-cat /) wertet jedes Argument nur nach Bedarf aus. – Thumbnail

+0

Ja, aber wie wenden Sie es auf eine Reihe von Argumenten an? –

+0

Müssen Sie wirklich die Ergebnisse verketten, oder möchten Sie sie nur träge konsumieren? –

Antwort

8

Für die Aufzeichnung apply nur genug von den Argumenten Sequenz verbrauchen, wie es die arity zu nennen für die vorgesehene Funktion muss bestimmen. Da die maximale Stelligkeit concat 3 ist, wird apply höchstens 3 Elemente aus der zugrunde liegenden Sequenz erkennen.

Wenn diese API-Aufrufe teuer sind und Sie es sich nicht leisten können, unnötige zu erstellen, dann benötigen Sie eine Funktion, die eine Seq-Of-Seqs akzeptiert und sie nacheinander verkettet. Ich glaube nicht, dass es etwas eingebautes gibt, aber es ist ziemlich einfach, dein eigenes zu schreiben:

(defn lazy-cat' [colls] 
    (lazy-seq 
    (if (seq colls) 
     (concat (first colls) (lazy-cat' (next colls)))))) 
+0

Vielen Dank für die Erläuterung zu bewerben und einen Vorschlag für faule Katze '. –

+0

nette Antwort; Übrigens hat diese Funktion bei der Verwendung von "next" 2 Elemente aus "colls" eifrig ausgewertet, selbst wenn nur 1 Bewertung erforderlich ist, z. '(erste (faule Katze 'Aseq))'. Die Verwendung von "rest" ergab stattdessen das erwartete Verhalten. – pestrella