Sto cercando di scrivere un modulo generico che permetta ai programmi Haskell di interagire con Cassandra. Il modulo dovrà mantenere il proprio stato. Ad esempio, avrà un pool di connessioni e un elenco di callback da richiamare quando viene salvato un nuovo record. Come dovrei strutturare il codice in modo che questo modulo possa mantenere il suo stato? Ecco alcuni degli approcci che ho preso in considerazione. Sono sulla buona strada? (Sono nuovo di Haskell e ancora imparando il modo migliore per pensare in modo funzionale.)Come strutturate un modulo stateful in Haskell?
Opzione 1:
Il modulo viene eseguito in un (StateT s IO) monade, dove s è lo stato globale per l'intero programma usando il modulo Cassandra. Naturalmente, poiché il modulo Cassandra può essere utilizzato da più programmi, i dettagli di ciò che è in s dovrebbero essere invisibili al modulo Cassandra. Il modulo dovrebbe esportare una classe di caratteri che gli consenta di estrarre CassandraState da s e reinserire un nuovo CassandraState in s. Quindi, qualsiasi programma che utilizza il modulo dovrebbe rendere il suo stato principale un membro di questa classe di tipi.
Opzione 2:
Il modulo viene eseguito in un (StateT CassandraState IO) monade. Ogni volta che qualcuno chiama un'azione nel modulo, dovrebbe estrarre il CassandraState da qualsiasi posizione in cui lo hanno nascosto, richiamare l'azione con runState e prendere lo stato risultante e riporlo nuovamente (ovunque).
Opzione 3:
Non mettere le funzioni del modulo Cassandra in una monade StateT a tutti. Invece, chiedi al chiamante di passare esplicitamente in CassandraState quando è necessario. Il problema con l'opzione 2 è che non tutte le funzioni nel modulo modificheranno lo stato. Ad esempio, l'ottenimento di una connessione modificherà lo stato e richiederà al chiamante di bloccare lo stato risultante. Tuttavia, per salvare un nuovo record è necessario leggere lo stato (per ottenere i callback), ma non è necessario modificare lo stato. L'opzione 2 non fornisce al chiamante alcun suggerimento che connetta cambi lo stato mentre crea no.
Ma, se mi allontano dall'uso della monade StateT e ho solo funzioni che contengono gli stati come parametri e restituiscono valori semplici o tuple di valori semplici e nuovi stati, allora è davvero ovvio per il chiamante quando lo stato ha bisogno da salvare. (Sotto le copertine del mio modulo, prenderei gli stati in arrivo e li costruirò in una monade (StateT CassandraState IO), ma i dettagli di questo sarebbero nascosti al chiamante.Quindi, per il chiamante, l'interfaccia è molto esplicita , ma sotto le coperte, è solo Opzione 2)
Opzione 4:
Qualcos'altro?
Questo problema deve verificarsi molto spesso quando si creano moduli riutilizzabili. Esiste una sorta di metodo standard per risolverlo?
(A proposito, se qualcuno conosce un modo migliore per interagire con Cassandra da Haskell che usare Thrift, per favore fatemelo sapere! Forse non devo scrivere questo a tutti. :-)
FYI - in 'modulo' cerchi Haskell è l'unità di compilazione, cioè un singolo file sorgente. Anche se in realtà non ho un nome migliore per quello che stai descrivendo, parlare di un "modulo" che ha stato mi ha buttato per un momento. –
Oops. Avrei dovuto dire "pacchetto" o "biblioteca". –