Conservazione del registro delle modifiche immutabili della struttura dati

2

Ho una struttura di dati immutabile ampia e complessa (il linguaggio è F #, ma dovrebbe essere applicabile a qualsiasi lingua) dove ho definito molte funzioni che apportano modifiche e restituisco nuove istanze di ds con firme come:

val action: ... -> ds:Ds<U> -> Ds<U> 

Quello che voglio è in qualche modo astrarre i cambiamenti avvenuti nella struttura dati dopo una serie di azioni diverse, in modo che la mia interfaccia utente controlli / strutture di dati di supporto abbiano un "delta" che possono usare per aggiornare in modo efficiente. Senza il "delta", la ricomposizione di tutti questi dati da zero sarebbe molto più costosa.

Un semplice esempio sarebbe una normale infrastruttura di lista immutabile con inserimenti e rimuove. Se questa struttura di dati viene utilizzata come dati di supporto di ListBox in UI, vorrei essere avvisato di modifiche come item A was removed , item B was added per aggiornare rapidamente il mio ListBox invece di svuotare il controllo e riempirlo di nuovo dopo ogni aggiornamento ds.

Come ti avvicineresti a un simile problema?

    
posta ghord 26.07.2016 - 08:14
fonte

1 risposta

2

Descrivo un possibile approccio. Definirei per prima cosa le operazioni che dovrebbero essere applicate alla struttura dei dati (se ho capito bene, l'hai già fatto). Usando la notazione Haskell (non ho familiarità con F #, spero che la notazione Haskell sia abbastanza intuitiva per te) per gli elenchi che avresti:

add    ::         a -> [a] -> [a]
remove :: Eq a => a -> [a] -> [a]

dove presumo che add sia solo l'operazione cons (:) , e remove è una funzione che rimuove la prima occorrenza dell'elemento specificato. Quindi, in Haskell queste sono già funzioni standard:

import Data.List(delete)

add    = (:)
remove = delete

Quindi utilizzerei un tipo di dati per le voci del registro:

data Action a = Add a | Remove a

Quindi la fonte delle modifiche alla struttura dei dati genera un flusso di azioni su un tipo specifico. Se il tuo elenco contiene stringhe, hai

actions :: [Action String]

La tua funzione di aggiornamento sarà

update :: Eq a => Action a -> [a] -> [a]
update (Add x)    = add x
update (Remove x) = remove x
...

Riassumendo:

  1. Si definiscono le operazioni elementari sulla struttura dei dati e si cerca di trovare un'implementazione efficiente per loro. Puoi trovare idee interessanti in Strutture dati puramente funzionali .
  2. Si definiscono le voci del registro come un tipo di dati con un costruttore di dati per operazione.
  3. L'origine delle azioni viene definita come produzione di un flusso di voci di registro.
  4. Tutte le posizioni nel codice che devono reagire alle azioni eseguono un flusso di voci di registro come voci di registro di input e di processo utilizzando la funzione di aggiornamento non appena sono disponibili.

Per ragioni di semplicità, ho definito la fonte delle azioni come una lista (pigra, possibilmente infinita). Ciò implicherebbe che i consumatori delle azioni debbano estrarre le voci di registro dalla loro origine. In un'applicazione GUI si preferisce spingere le voci di registro dalla loro origine ai vari componenti della GUI che devono essere aggiornati.

Quindi, l'ultimo aspetto che potresti dover considerare è come rendere la tua applicazione reattiva . (Forse hai già risolto questo problema nella tua applicazione, aggiungo solo alcuni suggerimenti per la completezza.) Quello di cui hai bisogno è di trasformare il tuo elenco infinito (flusso) di voci di registro in un osservabile, e lasciare che i consumatori osservabili applichino la funzione di aggiornamento alla loro copia locale della struttura dati. Nel caso tu sia interessato, ci sono sufficienti informazioni sulla programmazione reattiva in F # sulla rete, vedi per es. questo articolo .

    
risposta data 26.07.2016 - 11:41
fonte

Leggi altre domande sui tag