A little trouble upgrading to conduit 0.4.x

Hi all, I'm upgrading various bits and bobs to conduit 0.4.x, but I've hit a little snag with "sourceStateIO". The following function fails to compile:
sourceQuery :: Database -> String -> [SQLData] -> Source IO [SQLData] sourceQuery database sql parameters = sourceStateIO (do stmt <- SQL.prepare database sql return (Unbound,stmt)) (\(_,stmt) -> SQL.finalize stmt) (\(state,stmt) -> do -- Bind parameters if necessary. when (state == Unbound) $ do SQL.bind stmt parameters -- Fetch results. nextResult <- SQL.step stmt case nextResult of Done -> return StateClosed Row -> liftM (StateOpen (Bound,stmt)) $ SQL.columns stmt)
All the SQL.xyz bits run in the IO monad. This code runs fine in Conduit 0.2.x, but on Conduit 0.4.x it fails to compile with the following error: src/Data/CQRS/EventStore/Backend/Sqlite3Utils.hs:43:3: No instance for (resourcet-0.3.2:Control.Monad.Trans.Resource.MonadResource IO) arising from a use of `sourceStateIO' Possible fix: add an instance declaration for (resourcet-0.3.2:Control.Monad.Trans.Resource.MonadResource IO) In the expression: sourceStateIO [rest elided; just the rest of the definition of sourceQuery] In an equation for `sourceQuery': sourceQuery database sql parameters = sourceStateIO [rest elided; just the rest of the definition of sourceQuery] I can see that I'm missing an instance, but I can't seem to find a direct instance for MonadResource IO, nor can I tell which indirect instance could get me there. I there some specific import I need to get the necessary instances, or do I need to do something else? Regards,

On Wed, Apr 4, 2012 at 5:17 PM, Bardur Arantsson
Hi all,
I'm upgrading various bits and bobs to conduit 0.4.x, but I've hit a little snag with "sourceStateIO". The following function fails to compile:
sourceQuery :: Database -> String -> [SQLData] -> Source IO [SQLData] sourceQuery database sql parameters = sourceStateIO (do stmt <- SQL.prepare database sql return (Unbound,stmt)) (\(_,stmt) -> SQL.finalize stmt) (\(state,stmt) -> do -- Bind parameters if necessary. when (state == Unbound) $ do SQL.bind stmt parameters -- Fetch results. nextResult <- SQL.step stmt case nextResult of Done -> return StateClosed Row -> liftM (StateOpen (Bound,stmt)) $ SQL.columns stmt)
All the SQL.xyz bits run in the IO monad. This code runs fine in Conduit 0.2.x, but on Conduit 0.4.x it fails to compile with the following error:
src/Data/CQRS/EventStore/Backend/Sqlite3Utils.hs:43:3: No instance for (resourcet-0.3.2:Control.Monad.Trans.Resource.MonadResource IO) arising from a use of `sourceStateIO' Possible fix: add an instance declaration for (resourcet-0.3.2:Control.Monad.Trans.Resource.MonadResource IO) In the expression: sourceStateIO [rest elided; just the rest of the definition of sourceQuery] In an equation for `sourceQuery': sourceQuery database sql parameters = sourceStateIO [rest elided; just the rest of the definition of sourceQuery]
I can see that I'm missing an instance, but I can't seem to find a direct instance for MonadResource IO, nor can I tell which indirect instance could get me there. I there some specific import I need to get the necessary instances, or do I need to do something else?
Regards,
_______________________________________________ web-devel mailing list web-devel@haskell.org http://www.haskell.org/mailman/listinfo/web-devel
In conduit 0.2, a Source always implicitly wrapped up the inner monad in a ResourceT transformer. This caused complications, so now you need to explicitly add a ResourceT wrapper when it's needed. `sourceStateIO` is an example of such a function that requires the functionality of a `ResourceT`. Instead of making a requirements in the type that the inner monad be `ResourceT m`, there's a class constraint that the inner monad be an instance of `MonadResource`. tl;dr: Change your type signature to: sourceQuery :: Database -> String -> [SQLData] -> Source (ResourceT IO) [SQLData] You'll also need to call liftIO in a few places. HTH, Michael

On 04/04/2012 04:22 PM, Michael Snoyman wrote:
On Wed, Apr 4, 2012 at 5:17 PM, Bardur Arantsson
wrote: Hi all,
I'm upgrading various bits and bobs to conduit 0.4.x, but I've hit a little snag with "sourceStateIO". The following function fails to compile:
In conduit 0.2, a Source always implicitly wrapped up the inner monad in a ResourceT transformer. This caused complications, so now you need to explicitly add a ResourceT wrapper when it's needed. `sourceStateIO` is an example of such a function that requires the functionality of a `ResourceT`. Instead of making a requirements in the type that the inner monad be `ResourceT m`, there's a class constraint that the inner monad be an instance of `MonadResource`.
I'm wondering if I can just have a simple transPipe runResourceT $ sourceQuery ... wrapper so that old callers can remain unmodified. This would give the old callers the (Source IO [SQLData]) that they expect. As far as I can tell, the open/close behavior would not be modified by transPipe. Is there any reason that this wouldn't work? Regards,

On Apr 4, 2012 6:20 PM, "Bardur Arantsson"
On 04/04/2012 04:22 PM, Michael Snoyman wrote:
On Wed, Apr 4, 2012 at 5:17 PM, Bardur Arantsson
Hi all,
I'm upgrading various bits and bobs to conduit 0.4.x, but I've hit a
snag with "sourceStateIO". The following function fails to compile:
In conduit 0.2, a Source always implicitly wrapped up the inner monad in a ResourceT transformer. This caused complications, so now you need to explicitly add a ResourceT wrapper when it's needed. `sourceStateIO` is an example of such a function that requires the functionality of a `ResourceT`. Instead of making a requirements in the type that the inner monad be `ResourceT m`, there's a class constraint that the inner monad be an instance of `MonadResource`.
I'm wondering if I can just have a simple
transPipe runResourceT $ sourceQuery ...
wrapper so that old callers can remain unmodified. This would give the
wrote: little old callers the (Source IO [SQLData]) that they expect. As far as I can tell, the open/close behavior would not be modified by transPipe.
Is there any reason that this wouldn't work?
Regards,
_______________________________________________ web-devel mailing list web-devel@haskell.org http://www.haskell.org/mailman/listinfo/web-devel
Unfortunately that won't work, and would be very dangerous. In fact, I should update the docs to explain what transPipe does, and the limited cases in which it can work correctly. transPipe will call runResourceT on each individual monadic action performed by the Pipe in question. In this case, the result would be that runResourceT right after the first chunk of data is returned, which is certainly *not* what you want. The fact is that in version 0.2 of conduit, *every* Source, Sink, and Conduit lived in ResourceT. So if you want to keep things working the same way as before, just explicitly add the ResourceT wrappers. Your code already has a call to runResourceT somewhere to unwrap those. Possibly a better approach would be to use type variables for the monads in your type signature and start off with a `Monad m` context. Then GHC will tell you when you need to use liftIO (because m isn't IO) and when you need to change the context to MonadResource. I'll try to put together a larger example of this stuff in the next few days, but the combination of the upcoming Yesod release a Passover next week (and the requisite crunch at work) leaves me with less time than usual. Michael

On 04/04/2012 05:45 PM, Michael Snoyman wrote:
On Apr 4, 2012 6:20 PM, "Bardur Arantsson"
wrote: On 04/04/2012 04:22 PM, Michael Snoyman wrote:
On Wed, Apr 4, 2012 at 5:17 PM, Bardur Arantsson
Hi all,
I'm upgrading various bits and bobs to conduit 0.4.x, but I've hit a
snag with "sourceStateIO". The following function fails to compile:
In conduit 0.2, a Source always implicitly wrapped up the inner monad in a ResourceT transformer. This caused complications, so now you need to explicitly add a ResourceT wrapper when it's needed. `sourceStateIO` is an example of such a function that requires the functionality of a `ResourceT`. Instead of making a requirements in the type that the inner monad be `ResourceT m`, there's a class constraint that the inner monad be an instance of `MonadResource`.
I'm wondering if I can just have a simple
transPipe runResourceT $ sourceQuery ...
wrapper so that old callers can remain unmodified. This would give the
wrote: little old callers the (Source IO [SQLData]) that they expect. As far as I can tell, the open/close behavior would not be modified by transPipe.
Is there any reason that this wouldn't work?
Regards,
_______________________________________________ web-devel mailing list web-devel@haskell.org http://www.haskell.org/mailman/listinfo/web-devel
Unfortunately that won't work, and would be very dangerous. In fact, I should update the docs to explain what transPipe does, and the limited cases in which it can work correctly.
transPipe will call runResourceT on each individual monadic action performed by the Pipe in question. In this case, the result would be that runResourceT right after the first chunk of data is returned, which is certainly *not* what you want.
Ah, I see.
The fact is that in version 0.2 of conduit, *every* Source, Sink, and Conduit lived in ResourceT. So if you want to keep things working the same way as before, just explicitly add the ResourceT wrappers. Your code already has a call to runResourceT somewhere to unwrap those.
Yup, indeed it does -- I just wanted to try to minimize disruption. I'll do as you suggest and just let the (ResourceT IO) propagate outwards in the type signatures until it hits a runResourceT :).
Possibly a better approach would be to use type variables for the monads in your type signature and start off with a `Monad m` context. Then GHC will tell you when you need to use liftIO (because m isn't IO) and when you need to change the context to MonadResource.
Not sure what you mean here. Are you talking about starting with a maximally general type signature and then restricting based on the need for IO?
I'll try to put together a larger example of this stuff in the next few days, but the combination of the upcoming Yesod release a Passover next week (and the requisite crunch at work) leaves me with less time than usual.
Some examples would indeed be nice, but there's no rush :). Cheers,

On Wed, Apr 4, 2012 at 7:02 PM, Bardur Arantsson
On 04/04/2012 05:45 PM, Michael Snoyman wrote:
On Apr 4, 2012 6:20 PM, "Bardur Arantsson"
wrote: [--snip--]
Oh, and thanks for your help :).
Cheers,
_______________________________________________ web-devel mailing list web-devel@haskell.org http://www.haskell.org/mailman/listinfo/web-devel
OK, I started working on the "practical conduits" chapter of the Mezzo Haskell book. Hopefully it will be helpful. Feedback (and pull requests) welcome :) https://github.com/mezzohaskell/mezzohaskell/blob/master/chapters/libraries/... Michael
participants (2)
-
Bardur Arantsson
-
Michael Snoyman