
Tom Pledger writes:
By the way, how does the a in a -> b -> IO (b, Bool) work? It looks like it has something to do with the current row. Does doquery have to accommodate any possible substitution for a ?
I fired this off without thinking about it too much, and looking at the prelude type signatures for fold. The list being folded over is implied by the DB query, is accessible through the IO monad. Hence a parameter is not required. It would really be: doquery :: Process -> String -> b -> (b -> IO (b,Bool)) -> IO b
I don't have a preference, but offer this view of the options:
With an exception, "Stop, and return the last b you saw." With a boolean, "Stop, and return this b."
I think I like the behavior where, when the bool in the tuple is true, the b in the tuple is immediately returned from the query. Exceptions would be propagated to the caller of doquery without modification (but with appropriate cleanups). One thing that I am unsure about is whether the column value accessing functions that I specified before stringv :: Process -> CInt -> IO String doublev :: Process -> CInt -> IO Double intv :: Process -> CInt -> IO Int should return actions in the IO monad as above, or instead should be in some other DBQuery monad, that trivially extends the IO monad, but is only valid inside the doquery call. This would have the benefit of restricting the column access functions to inside a query via the type system. I'd also probably use a typeclass to specify a single colv function. ie: class DBCol a where colv :: DBQuery a instance DBCol String where... instance DBCol Double where... doquery :: Process -> String -> b -> (b -> DBQuery (b,Bool)) -> IO b Any comments? Tim

Tim Docker writes: : | The list being folded over | is implied by the DB query, is accessible through the IO monad. | Hence a parameter is not required. It would really be: | | doquery :: Process -> String -> b -> (b -> IO (b,Bool)) -> IO b : | One thing that I am unsure about is whether the column value | accessing functions that I specified before | | stringv :: Process -> CInt -> IO String | doublev :: Process -> CInt -> IO Double | intv :: Process -> CInt -> IO Int | | should return actions in the IO monad as above, or instead should | be in some other DBQuery monad, that trivially extends the IO monad, | but is only valid inside the doquery call. This would have the benefit | of restricting the column access functions to inside a query via the | type system. How about introducing a Cursor abstract data type? doquery :: Process -> String -> b -> (Cursor -> b -> IO (b, Bool)) -> IO b stringv :: Cursor -> CInt -> IO String doublev :: Cursor -> CInt -> IO Double intv :: Cursor -> CInt -> IO Int This achieves the restriction you're after, because doquery is the only exported producer of Cursor, and stringv etc. are the only exported consumers of Cursor. It also has the benefit that the function you pass to doquery can make other calls to doquery, without mucking up the 'current row' state. There would be one current row per Cursor, not one per Process. | I'd also probably use a typeclass to specify a single colv function. | ie: | | class DBCol a where | colv :: DBQuery a | | instance DBCol String where... | instance DBCol Double where... Good idea. The user can always use explicit type signatures to resolve ambiguity, and even then the code size will be about the same as with stringv etc. - Tom
participants (2)
-
Tim Docker
-
Tom Pledger