2011-01-03 11 views
18

Desidero creare un'astrazione che rappresenti una tabella di database, ma a cui è possibile accedere utilizzando tutti i soliti Clojure seq e conj e tutto ciò che è di fantasia. C'è un protocollo che devo aggiungere?In Clojure come posso implementare interfacce di raccolta Clojure standard sui miei record e tipi?

+1

C'è un motivo per cui un vettore di record è insufficiente come rappresentazione? (Voglio dire questo come una domanda seria, non snark). Tutte le API di chiusura funzionerebbero con una tale astrazione. Dalla logica di clojure http://clojure.org/rationale - "È meglio avere 100 funzioni che operano su una struttura dati piuttosto che 10 funzioni su 10 strutture dati". - Alan J. Perlis –

+0

Il motivo è che quando aggiungo un elemento al vettore voglio che l'elemento sia automaticamente conservato su un datastore, e non c'è modo che possa nasconderlo senza reimplementare conj o cons o qualsiasi altra cosa sia la funzione add. per i vettori. – Zubair

+3

Sii super, super attento con questo genere di cose. Se DB non è immutabile, stai mentendo sulla tua semantica a Clojure, questo può andare storto molto velocemente. La maggior parte di Clojure si basa sull'idea che le collezioni sono immutabili. In questo modo vengono formulate molte ipotesi su come funzionano determinate funzioni. Ad esempio, l'uso di conj su una collezione non dovrebbe modificare la collezione. Dovrebbe restituire una nuova collezione. La violazione di questa regola potrebbe far fallire le funzioni di Clojure in modi molto strani. –

risposta

15

Sì. Il protocollo è definito dall'interfaccia Java clojure.lang.ISeq. Si consiglia di estendere clojure.lang.ASeq che fornisce un'implementazione astratta di esso.

Ecco un esempio: un'astrazione seq di una risorsa che è chiudibile e viene chiusa automaticamente quando termina lo seq. (Non rigorosamente testato)

(deftype CloseableSeq [delegate-seq close-fn] 
    clojure.lang.ISeq 
    (next [this] 
     (if-let [n (next delegate-seq)] 
     (CloseableSeq. n close-fn) 
     (.close this))) 
    (first [this] (if-let [f (first delegate-seq)] f (.close this))) 
    (more [this] (if-let [n (next this)] n '())) 
    (cons [this obj] (CloseableSeq. (cons obj delegate-seq) close-fn)) 
    (count [this] (count delegate-seq)) 
    (empty [this] (CloseableSeq. '() close-fn)) 
    (equiv [this obj] (= delegate-seq obj)) 
    clojure.lang.Seqable 
    (seq [this] this) 
    java.io.Closeable 
    (close [this] (close-fn))) 
+0

Così uso la sintassi extendprotocol? – Zubair

+0

Aggiornamento della risposta con un esempio. –

+0

Brillante, grazie – Zubair