MonadPeelIO instance for monad transformers on top of "forall"

Hi Anders, I'm using your monad-peel package to good effect in my project, but I'm having trouble lifting peelIO through a particular monad. What follows is a simplified description of my problem. Say I have this monad: {{{ data M a = M { unM :: forall m. MonadPeelIO m => Reader.ReaderT () m a } instance Monad M where return x = M (return x) M mx >>= fxmy = M $ mx >>= unM . fxmy instance MonadIO M where liftIO io = M (liftIO io) }}} It seems "clear" that there should be a MonadPeelIO instance for M, but I can't for the life of me figure it out. I've tried: {{{ instance MonadPeelIO M where peelIO = M (fmap (\peel (M mx) -> liftM M (peel mx)) peelIO) }}} But this is not polymorphic enough: the peelIO gives me back a function (ReaderT () m a -> IO (ReaderT () m a)) for some *fixed* m, so I can't pack the result of that function into an M again using (liftM M). Have you (or the big brains on Haskell-Cafe, who are CCed) come across this before? Is there an obvious solution I am missing? Cheers, Max

On Fri, 4 Feb 2011, Max Bolingbroke wrote:
data M a = M { unM :: forall m. MonadPeelIO m => Reader.ReaderT () m a }
Maybe this won’t help in your actual code, but isn’t M isomorphic to IO (via unM :: M a -> IO a, M . liftIO :: IO a -> M a)? instance MonadPeelIO M where peelIO = M (liftIO (liftM (\k (M mx) -> liftM (\my -> (M (liftIO my))) (k mx)) peelIO)) Anders

On 4 February 2011 21:41, Anders Kaseorg
On Fri, 4 Feb 2011, Max Bolingbroke wrote:
data M a = M { unM :: forall m. MonadPeelIO m => Reader.ReaderT () m a }
Maybe this won’t help in your actual code, but isn’t M isomorphic to IO (via unM :: M a -> IO a, M . liftIO :: IO a -> M a)?
Well, yes :-). My real code actually has a non-trivial ReaderT transformer and a StateT transformer it reaches "m". I had hoped that by restricting to ReaderT () the problem would be simpler and hence clearer.
instance MonadPeelIO M where peelIO = M (liftIO (liftM (\k (M mx) -> liftM (\my -> (M (liftIO my))) (k mx)) peelIO))
This doesn't type check for me (I think the root of the trouble is you peelIO in the IO monad, but then later do (k mx) where mx is not an IO computation). Is this definition trying to exploit the isomorphism, or do you think that this is a solution to the general class of problems I'm having trouble with? Thanks for your reply! Max

On Fri, 4 Feb 2011, Max Bolingbroke wrote:
On 4 February 2011 21:41, Anders Kaseorg
wrote: On Fri, 4 Feb 2011, Max Bolingbroke wrote:
data M a = M { unM :: forall m. MonadPeelIO m => Reader.ReaderT () m a }
Maybe this won’t help in your actual code, but isn’t M isomorphic to IO (via unM :: M a -> IO a, M . liftIO :: IO a -> M a)?
Well, yes :-). My real code actually has a non-trivial ReaderT transformer and a StateT transformer it reaches "m". I had hoped that by restricting to ReaderT () the problem would be simpler and hence clearer.
Oh sorry, I further simplified your problem by stripping off the ReaderT () and forgot to undo that before sending my reply. Pretend that I sent the following instead: :-) Maybe this won’t help in your actual code, but isn’t M isomorphic to ReaderT () IO (via unM :: M a -> ReaderT () IO a, M . mapReaderT liftIO :: IO a -> M a)? instance MonadPeelIO M where peelIO = M (mapReaderT liftIO (liftM (\k (M mx) -> liftM (\my -> (M (mapReaderT liftIO my))) (k mx)) peelIO))
Is this definition trying to exploit the isomorphism, or do you think that this is a solution to the general class of problems I'm having trouble with?
It does exploit the isomorphism. I’m not sure whether the isomorphism will generalize to your case; I assume there’s probably some reason you have a polymorphic type instead of replacing it with an equivalent nonpolymorphic type? Anders

On Fri, 4 Feb 2011, Anders Kaseorg wrote:
but isn’t M isomorphic to ReaderT () IO (via unM :: M a -> ReaderT () IO a, M . mapReaderT liftIO :: IO a -> M a)?
Er, M . mapReaderT liftIO :: ReaderT () IO a -> M a. Of course that doesn’t actually type check until you eta-expand it: (\x -> M (mapReaderT liftIO x)) :: ReaderT () IO a -> M a. Just to demonstrate that I didn’t use the triviality of ReaderT (), here’s a less trivial example with ReaderT and StateT: data M a = M { unM :: forall m. MonadPeelIO m => ReaderT Int (StateT Char m) a } instance Monad M return x = M (return x) M mx >>= fxmy = M (mx >>= unM . fxmy) instance MonadIO M where liftIO io = M (liftIO io) -- M ≅ ReaderT Int (StateT Char IO) fromM :: M a -> ReaderT Int (StateT Char IO) a fromM = unM toM :: ReaderT Int (StateT Char IO) a -> M a toM mx = M (mapReaderT (mapStateT liftIO) mx) instance MonadPeelIO M where peelIO = toM (liftM (\k (M mx) -> liftM toM (k mx)) peelIO) Anders

On 5 February 2011 04:19, Anders Kaseorg
Just to demonstrate that I didn’t use the triviality of ReaderT (), here’s a less trivial example with ReaderT and StateT:
This is superb, thank you! I would never have come up with that :-) It still seems to fail somehow on my real example, but I'm confident I can get it working now. Many thanks! Max

Hi Max, data M a = M { unM :: forall m. MonadPeelIO m => Reader.ReaderT () m a }
It seems "clear" that there should be a MonadPeelIO instance for M, but I can't for the life of me figure it out.
Have you (or the big brains on Haskell-Cafe, who are CCed) come across this before? Is there an obvious solution I am missing?
I have not used monad-peel before so please ignore my comment if I am missing something obvious. The documentation mentions that "Instances of MonadPeelIO should be constructed via MonadTransPeel, using peelIO = liftPeel peelIO". I think this would work at least in your simplified example as ReaderT is an instance of MonadTransPeel. Maybe you can take the same route with your actual transformer? Sebastian

On 5 February 2011 02:35, Sebastian Fischer
I have not used monad-peel before so please ignore my comment if I am missing something obvious. The documentation mentions that "Instances of MonadPeelIO should be constructed via MonadTransPeel, using peelIO = liftPeel peelIO". I think this would work at least in your simplified example as ReaderT is an instance of MonadTransPeel. Maybe you can take the same route with your actual transformer?
I did indeed try this, but the error message was even more incomprehensible than my attempt to lift the MonadPeelIO (ReaderT () IO) instance directly! My reading of the error was that it suffers from the same problem (too little polymorphism). Cheers, Max
participants (3)
-
Anders Kaseorg
-
Max Bolingbroke
-
Sebastian Fischer