2014-10-27 20 views
7

Ecco una domanda per principianti: esiste un modo in Clojure per concatenare pigramente un numero arbitrario di sequenze? So che c'è la macro lazy-cat, ma non riesco a pensare alla sua applicazione corretta per un numero arbitrario di sequenze.Concatenazione pigra della sequenza in Clojure

Il mio caso d'uso è lazy che carica i dati da un'API tramite richieste impaginate (compensate/limitate). Ogni richiesta eseguita tramite request-fn sotto recupera 100 risultati:

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

Quando non ci sono più risultati, request-fn restituisce una sequenza vuota. Questo è quando mi fermo l'iterazione:

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

Ad esempio, l'API potrebbe tornare fino a 500 risultati e può essere deriso come:

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

Se voglio concatenare i risultati, posso usare (apply concat results) ma che valuta con entusiasmo la sequenza di risultati:

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

esiste un modo come concatenare la sequenza di risultati pigramente, utilizzando lazy-cat o qualcos'altro?

+0

Il [ 'pigro-cat' * macro *] (http://grimoire.arrdem.com/1.6. 0/clojure.core/lazy-cat /) valuta ogni argomento solo come richiesto. – Thumbnail

+0

Sì, ma come si applica a una sequenza di argomenti? –

+0

Hai davvero bisogno di concatenare i risultati o vuoi semplicemente consumarli pigramente? –

risposta

8

Per la registrazione, apply consumerà solo una quantità sufficiente della sequenza di argomenti in quanto è necessario determinare quale funzione chiamare per la funzione fornita. Poiché il numero massimo di concat è 3, apply realizzerà al massimo 3 elementi dalla sequenza sottostante.

Se queste chiamate API sono costose e davvero non puoi permetterti di renderle inutili, allora avrai bisogno di una funzione che accetta un seq-of-seq e li concatena pigramente uno alla volta. Non credo che ci sia niente di built-in, ma è abbastanza semplice per scrivere il proprio:

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

Grazie per il chiarimento su applicare e un suggerimento per il gatto pigro '. –

+0

bella risposta; btw, quando si usa 'next' questa funzione ha valutato avidamente 2 elementi da' colls' anche quando richiedeva solo una valutazione, ad es. '(prima (lazy-cat 'aseq))'. L'uso di 'rest' invece ha dato il comportamento previsto. – pestrella

Problemi correlati