2010-06-24 20 views
14

Sto sviluppando una struttura dati complessa in Clojure con più sotto strutture.Estrazione dai dettagli di implementazione della struttura dati in Clojure

So che vorrò estendere questa struttura nel tempo e, a volte, vorrò cambiare la struttura interna senza rompere i diversi utenti della struttura dati (ad esempio, potrei voler cambiare un vettore in una hashmap, aggiungere qualche tipo di struttura di indicizzazione per motivi di prestazioni, o incorporare un tipo Java)

mio pensiero attuale è:

  • definire un protocollo per la struttura complessiva con i vari metodi di accesso
  • Creare una mini-biblioteca di funzioni che navigano nella struttura dei dati e .es. (Query-sottostruttura-abc param1 param2)
  • Implementare la struttura di dati utilizzando defrecord o DEFTYPE, con i metodi di protocollo definiti di utilizzare la mini-biblioteca

Penso che questo funzionerà, anche se sono preoccupato che sta iniziando a somigliare a un sacco di codice "colla". Inoltre, probabilmente riflette anche la mia maggiore familiarità con gli approcci orientati agli oggetti.

Qual è il modo consigliato per farlo in Clojure?

risposta

11

Penso che il deftype potrebbe essere la strada da percorrere, tuttavia vorrei prendere un passaggio sui metodi di accesso. Invece, guarda su clojure.lang.ILookup e clojure.lang.Associative; queste sono interfacce che, se le implementate per il tuo tipo, ti permetteranno di usare get/get-in e assoc/assoc-in, rendendo la soluzione molto più versatile (non solo sarai in grado di cambiare l'implementazione sottostante, ma forse anche di usare funzioni costruite sulla libreria di raccolte standard di Clojure per manipolare le strutture).

Un paio di cose da notare:

  1. Probabilmente si dovrebbe cominciare con defrecord, utilizzando get, assoc & Co. con lo standard defrecord implementazioni di ILookup, Associative, IPersistentMap e java.util.Map. Potresti riuscire ad andare molto lontano con esso.

    Se/quando questi non bastano più, consultare le origini di emit-defrecord (una funzione privata definita in core_deftype.clj nelle origini di Clojure). È piuttosto complesso, ma ti darà un'idea di ciò che potresti aver bisogno di implementare.

  2. deftypedefrecord attualmente definiscono per voi qualsiasi funzione di fabbrica, ma probabilmente dovreste farlo da soli. Il controllo della sanità mentale va all'interno di quelle funzioni (e/o dei test corrispondenti).

  3. Le operazioni più concettualmente complesso sono, naturalmente, una misura perfetta per le funzioni di protocollo costruita sulle fondamenta di get & Co.

Oh, e dare un'occhiata a gvec.clj nelle fonti di Clojure per un esempio di potrebbe sembrare un serio codice di struttura dati scritto usando deftype.La complessità qui è di un tipo diverso da quello che descrivi nella domanda, ma ancora, è uno dei pochi esempi di programmazione di strutture dati personalizzate in Clojure attualmente disponibili per il consumo pubblico (ed è ovviamente un codice di qualità eccellente).

Ovviamente questo è proprio quello che il mio intuito mi dice in questo momento. Non sono sicuro che ci siano molti idiomi consolidati in questa fase, che con deftype non siano stati effettivamente rilasciati e tutti. :-)

+0

Grazie Michal! Insightful as ever :-) esaminerà sicuramente le opzioni ILookup e Associative – mikera

+0

Questa è una risposta molto utile! Ma quasi tre anni dopo sarebbe bello aggiornare questo (o creare una nuova risposta) in base alla funzionalità ora disponibile in 1.5. Una cosa che ho notato è che 'defrecord' ora emette funzioni di fabbrica, non so quali altre modifiche potrebbero influenzare questa risposta. –

+0

Penso che questa risposta possa usare anche un aggiornamento - anche il libro O'Reily Clojure ora dice che il defrecord del clojure crea funzioni di fabbrica. – djhaskin987

Problemi correlati