Alcune cose sono ancora implementate come interfacce Java in Clojure; di quelli, direi che alcuni rimarranno per sempre in questo modo per facilitare la collaborazione con il codice Clojure da altre lingue JVM.
Fortunatamente, quando si definisce un tipo utilizzando deftype
, si può avere il nuovo tipo implementare qualsiasi interfaccia Java richiesta (che Brian ha menzionato in un commento sopra), nonché qualsiasi metodo di java.lang.Object
. Un esempio per abbinare il vostro descrizione potrebbe essere simile a questo:
(deftype Foo [a b]
clojure.lang.IPersistentCollection
(seq [self] (if (seq a) self nil))
(cons [self o] (Foo. a (conj b o)))
(empty [self] (Foo. [] []))
(equiv
[self o]
(if (instance? Foo o)
(and (= a (.a o))
(= b (.b o)))
false))
clojure.lang.ISeq
(first [self] (first a))
(next [self] (next a))
(more [self] (rest a))
Object
(toString [self] (str "Foo of a: " a ", b: " b)))
Un esempio di cosa si può fare con esso al REPL:
user> (.toString (conj (conj (Foo. [] []) 1) 2))
"Foo of a: [], b: [1 2]"
user> (.toString (conj (conj (Foo. [:a :b] [0]) 1) 2))
"Foo of a: [:a :b], b: [0 1 2]"
user> (first (conj (conj (Foo. [:a :b] [0]) 1) 2))
:a
user> (Foo. [1 2 3] [:a :b :c])
(1 2 3)
Si noti che il REPL stampa come un ss; Credo che sia a causa dell'implementazione in linea di clojure.lang.ISeq
. È possibile saltarlo e sostituire il metodo seq
con uno che restituisce (seq a)
per una rappresentazione stampata utilizzando l'toString
personalizzato. str
utilizza sempre toString
, tuttavia.
Se è necessario il comportamento personalizzato delle funzioni familiari pr
(incluso println
ecc.), Sarà necessario implementare un numero personalizzato print-method
per il proprio tipo. print-method
è un multimetodo definito in clojure.core
; dare un'occhiata a core_print.clj nelle fonti di Clojure per esempio implementazioni.
fonte
2010-05-31 18:51:56
Non ancora dal momento che quasi nessun fn di basso livello (tranne ridurre) è stato "protocollo" ma è possibile utilizzare defrecord o deftype per definire un tipo di dati che si comporta come si desidera. – cgrand
Sì, ma poi devo implementare le funzioni che agiscono anche su di esso, creando nomi di funzioni ridondanti, come head che funziona come prima cosa per la mia struttura dati, no? –
Se si utilizza deftype, è possibile fornire implementazioni per le varie interfacce utilizzate da Clojure (come clojure.lang.ISeq) che fanno ciò che si desidera. – Brian