Domanda Estrazione dai dettagli di implementazione della struttura dati in Clojure


Sto sviluppando una complessa struttura dati in Clojure con più sottostrutture.

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 indicizzazione struttura per motivi di prestazioni, o incorporare un tipo Java)

Il mio pensiero attuale è:

  • Definire un protocollo per la struttura generale con vari metodi di accesso
  • Crea una mini-libreria di funzioni che navigano nella struttura dei dati, ad es. (query-substructure-abc param1 param2)
  • Implementare la struttura dei dati utilizzando defrecord o deftype, con i metodi di protocollo definiti per utilizzare la mini-libreria

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

Qual è il modo consigliato per farlo in Clojure?


14
2018-06-24 13:26


origine


risposte:


penso che deftype potrebbe essere la strada da percorrere, tuttavia vorrei fare un passaggio sui metodi di accesso. Invece, guarda dentro 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, creando una soluzione molto più versatile (non solo sarai in grado di cambiare l'implementazione sottostante, ma forse anche di usare le funzioni costruite sulla libreria delle collezioni standard di Clojure per manipolare le tue strutture).

Un paio di cose da notare:

  1. Probabilmente dovresti iniziare con defrecord, usando 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ù, dai un'occhiata alle fonti per emit-defrecord (una funzione privata definita in core_deftype.clj nelle fonti di Clojure). È piuttosto complesso, ma ti darà un'idea di ciò che potresti aver bisogno di implementare.

  2. Nessuno dei due deftype né defrecord al momento definisci per te qualsiasi funzione di fabbrica, ma probabilmente dovresti farlo tu stesso. Il controllo della sanità mentale va all'interno di quelle funzioni (e / o dei test corrispondenti).

  3. Le operazioni più concettualmente complesse sono naturalmente perfettamente adatte per le funzioni di protocollo costruite sulla base di get & Co.

Oh, e dai un'occhiata gvec.clj nelle fonti di Clojure per un esempio di ciò che è stato scritto con un codice di struttura dati serio deftype potrebbe sembrare. 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 mi dice la mia intuizione in questo momento. Non sono sicuro che ci sia molto in termini di idiomi affermati in questa fase, con deftype in realtà non è stato rilasciato e tutto. :-)


11
2018-06-24 17:46