You can clone with
HTTPS or Subversion.
Would it be possible to change fold and friends to accept a MonadIO instead of specifically IO?
Yes, I do very much plan on doing this. My hangup at the moment is that generalizing withTransaction requires committing to a solution to deal with exceptions, and I'm really none too enthusiastic about either MonadCatchIO or monad-control. I suppose I could generalize functions that don't require dealing with exceptions inside the generalized monad, however.
Also, beware that I have not tested fold extensively. And in particular there are some caveats with using fold when the database returns columns whose type is not included in BuiltinTypes, as noted in commit bce0d38.
You could also use Data.Conduit
Data.Conduit uses monad-control. And I see your point with regard to fold; it's far less useful in it's ungeneralized state, potentially requiring some rather unnatural and ugly circumlocutions.
One of the problems with the current implementation of fold is that the database connection is left in the wrong state if the function it is passed throws an exception. So I do need the ability to deal with exceptions.
And, honestly, I could probably close my eyes and temporarily forget about the things that MonadCatchIO and monad-control get wrong, but I don't like the fact that I'd basically have to pick between the Yesod and Snap worlds, delegating one of them to a second-class citizen.
Although, it is somewhat unfortunate that packages that provide a monad (such as Yesod and Snap) don't supply instances for both alternatives. But you actually have to pick one when you provide a function that must deal with exceptions thrown by functional arguments, such as withTransaction and fold.
If you are willing to say, what does your monad stack look like out of curiousity?
I've been trying to find a set of suitable libraries that can play nice together for a pretty simple web backend and have been largely disappointed. I'm at that point where i'll just do whatever and move on. Right now i was using CGIT IO.
Oh fun, now we are talking three ways of catching exceptions, MonadCatchIO-mtl, MonadCatchIO-transformers, and monad-control. I'd forgotten that MonadCatchIO-mtl and MonadCatchIO-transformers are completely separate, incompatible packages. (though of a similar flavor, whereas monad-control is different)
And none of which get things correct. Though I don't really know what the correct thing is, exactly.
This issue has been frustrating me; it's something the Haskell community really needs to get serious about fixing.
How important is streaming to your intended application? You could generalize query and execute yourself, which need not be concerned with controlling exceptions. Also, you could open a cursor for your query and implement streaming through query and execute alone...
The temporary solution i ended up going with is just wrapping up connect, query, execute and the transaction stuff in a ResourceT and providing queryList and querySource. The Source in querySource will obviously load everything into memory instead of actually streaming, but i plan to fix that in the future when i have time.
Well, using a database cursor is not particularly difficult. See close, declare, fetch, and move for details.
In the project I'm currently working on I've been rewriting the with* functions so that they work on any (MonadIO m, MonadCatch m). MonadCatch is from the exceptions package by Edward Kmett.
(MonadIO m, MonadCatch m)
I don't yet know what are the pros and cons of MonadCatch over any of the alternatives, but I know that is very straightforward to use and that it plays well with pipes-safe which is another library I'm using in my project. Unless I discover some shortcomings or some of you tell me that MonadCatch is not a good approach, I'll continue to research its limitations and hopefully prepare a pull request embracing MonadIO and MonadCatch throughout the library.
So, I thought I'd mention that in case someone wants to yell at me :)
Yeah, the exceptions package is very much in the spirit of MonadCatchIO, though with the updated mask functions and with some of the problematic instances removed. Honestly, I think I like that better than the apparently ascendant monad-control, which I'm not particularly fond of.
My one possible misgiving about exceptions is that bracket isn't in the typeclass, or possibly a separate typeclass. I've heard rumors that people suspect there are monads that can implement bracket but not catch. But this is not something I understand well enough to make a substantive comments about.
My inclination at this point is to adopt monad-control when (if?) Snap migrates to it.
fyi: snap 1.0 will use monad-control (see its HEAD cabal file.)