2014-09-25 16 views
5

Nella mia applicazione memorizzo e carico oggetti da un database (attualmente un file flat locale ...). Questi oggetti appartengono tutti a una famiglia di tipi Event a e sono anche tutti serializzabili a/da ByteString. Ma il a nella famiglia tipo può variare ...Come gestire la deserializzazione generica in haskell?

Ecco la dichiarazione della classe di base:

class BusinessModel a where 
    data Event a :: * 
    apply :: a -> Event a -> a 

E un esempio di implementazione, insieme ai tipi necessari:

data User = User { userId :: UserId, userName :: Text } deriving (Eq, Show, Read, Generic) 

instance ToJSON User 
instance FromJSON User 

type UsersView = M.Map UserId User 

instance BusinessModel UsersView where 

    data Event UsersView = NoEvent    -- ^A no-op event 
         | UserRegistered User 
         deriving (Eq, Show, Read, Generic) 

    apply v (UserRegistered u) = insert (userId u) u v 
    apply v _     = v 

Ecco il interfaccia corrente al mio negozio di eventi:

class (MonadIO store) => EventStore store where 
    -- store a single event 
    store :: Serializable s => s -> store() 
    -- load all events from the store 
    load :: Serializable s => store [s] 

Quindi dobbiamo essere abl e per puntate eventi (qui usiamo semplicemente la rappresentazione JSON:

instance ToJSON (Event UsersView) 
instance FromJSON (Event UsersView) 

instance Serializable (Event UsersView) where 
    read = fromJust . decode 
    write = encode 

Vorrei essere in grado di deserialise tutte le stored Event a oggetti, per tutti a, quindi applicare ogni Event a alla corretta a all'interno di una struttura che contiene eventi diversi "target". Quando provo a usare in modo ingenuo lo load, mi imbatto nel problema di avere più istanze di Serializable e di non essere in grado di scegliere quello giusto.

Fuori dalla cima della mia testa, ho potuto pensare ad una soluzione semplice: tagga ogni evento da leggere con l'appropriato a a cui appartiene, ma questo non sembra molto elegante?

Qual è l'approccio migliore a questo tipo di problema?

+1

Contrassegna ogni evento con l'appropriato 'a'. –

+0

Grazie. Avete indicazioni su codice/pacchetto che fanno cose simili? Immagino di non essere il primo a implementarlo. – insitu

+0

Il pacchetto aeson fa qualcosa di simile-ish, che potrebbe essere un posto dove guardare. Sto ancora sperando che qualcuno possa dare una risposta migliore. –

risposta

2

In Haskell non esiste un metodo automatico pratico per ciò che si sta tentando di fare. Deserializzare valori arbitrari e utilizzarli in modi polimorfi di run-time tramite interfacce è più di un modello orientato agli oggetti.

Come hai detto tu stesso, per la serializzazione e la deserializzazione devi taggare gli eventi in qualche modo per memorizzare e ripristinare le informazioni sul tipo. Per esempio.

data TaggedEvent 
    = EventUsersView (Event UsersView) 
    | EventSomeOtherView (Event SomeOtherView) 
    ... 

per rimuovere alcuni boilerplate manuale, il tipo di TaggedEvent potrebbe essere generato automaticamente utilizzando Template Haskell come avviene ad esempio per gli eventi in acid-state.

+0

Grazie per la risposta. Quale sarebbe uno schema funzionale adeguato per quello che sto cercando di fare? Sto implementando un'applicazione basata su eventi dove lo stato di applicazione è transitorio, immutabile e modificato attraverso eventi, essendo quest'ultima l'unica parte persistente del sistema. AFAICT, questo è in genere funzionale. – insitu

+0

FWIW, ho implementato l'approccio basato su tag che è suggerito in questa domanda: http: // StackOverflow.it/questions/26117165/how-to-handle-or-avoid-blockedindefinitelyonstm-exception Ho dovuto giocherellare un po 'con le classi di digitazione e tipo corretto per garantire che le viste non abbiano alcuna conoscenza di questo tag, ma funziona correttamente. – insitu

Problemi correlati