I\'m looking to write a generic module that allows Haskell programs to interact with Cassandra. The module will need to maintain its own state. For example, it will have a con
I'd go with Option 2. Users of your module shouldn't use runState
directly; instead, you should provide an opaque Cassandra
type with an instance of the Monad
typeclass and some runCassandra :: Cassandra a -> IO a
operation to "escape" Cassandra. The operations exported by your module should all run in the Cassandra
monad (e.g. doSomethingInterestingInCassandra :: Int -> Bool -> Cassandra Char
), and their definition can access the wrapped CassandraState
.
If your users need some additional state for their application, they can always wrap a monad transformer around Cassandra
, e.g. StateT MyState Cassandra
.
Something like the HDBC model would be to have an explicit CassandraConnection
data type. It has an MVar inside with some mutable state. Since all your actions are in IO anyway I'd imagine, they can just take the CassandraConnection as an argument to these actions. The user then can pack that connection into a state or reader monad, or thread it explicitly, or do whatever they want.
Internally you can use a monad or not -- that's really your call. However, I favor APIs that when possible don't force users into any particular monad unless truly necessary.
So this is a sort of version of option 3. But the user shouldn't really care whether or not they're changing the connection state -- at that level you can really hide the details from them.