2006/8/11, Stefan Aeschbacher <<a href="mailto:firstname.lastname@example.org" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">email@example.com</a>>:<div><span class="gmail_quote"></span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hi<br><br>I'm trying to understand Monad Transformers. The code below works as<br>expected but I have the following questions:<br> - why can I use liftIO but not lift in the doSomething function?</blockquote><div><br>I will first try to explain why it is not possible to use lift.
<br><br>Short version : In the definition of MyM<br><br><blockquote style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;" class="gmail_quote">type MyM a = WriterT [Entry] (ReaderT MyData IO) a
<br></blockquote><br>WriterT is parameterized with a *fixed* monad type, namely (ReaderT MyData IO). <br>But in order to be able to instantiate MonadTrans and defining lift, this value has to be a parameter. <br>The parameter should then take on different values, depending on which monad to lift.
<br>I.e. MyM a = ... should instead look like MyM m a = ... <br><br>Longer version:<br><br>Looking at the definition of MonadTrans and lift one sees that lift, <br>given a monadic value, produces a transformed version of this monad.
<br><br>class MonadTrans t where<br> lift :: Monad m => m a -> t m a
<br><br>In the case with the 'doSomething function', we wish to lift an action of type (IO ()) into MyM. <br><br>So, what is the generell type of 'lift (some IO () action)' , e.g lift (putStr "hello") ? <br><br>
Examining the definition of lift above (or using :t ) , concludes that : <br><br>lift (putStr "hello") :: MonadTrans t => t IO (). <br><br>Due to the type of 'doSomething' (doSomething :: MyM Int)<br>the monad transformer 't' should have type MyM, making the result of the lift operation MyM IO ().
<br><br>However, this is where it fails. According to the definition of MyM it canīt be parameterised <br>with more than one type (not with both IO and ()). <br><br>But, a monad transformer MUST have kind ((* -> *) -> * -> *) in order to
<br>be able to create a valid return type for lift. So even if we wished to<br>write our own instance for MonadTrans MyM, it wouldn't be possible.<br><br>Compare with the following example which on the other hand does work with lift.
<br><br>type MyM2 m a = WriterT [Entry] m a<br><br>doSomethingElse :: MyM2 IO Int<br>doSomethingElse = do<br> lift $ putStrLn "hello"<br> return 2<br><br>Now, MyM2 has the right kind. And since (WriterT w) ,for any Monoid w, instantiates
<br>the MonadTrans class, it is possible to use the lift function to produce a value of type MyM2 IO ().<br><br>So, why does liftIO work ? Consider the definition of MonadIO :<br><br>class (Monad m) => MonadIO m where
liftIO :: IO a -> m a<br><br>The monad that should embed the IO action (m above) has kind (* -> *). <br>This makes an instance for MyM possible. Because MyM is a synonym for a WriterT monad,<br>an instance for this is allready defined in the
Controll.Monad.WriterT module:<br><br>instance (Monoid w, MonadIO m) => MonadIO (WriterT w m) where<br> liftIO = lift . liftIO<br> <br>Actually it also requires that the inner monad, i.e. ReaderT in this case, also instantiates the MonadIO, which luckily it does :)
<br><br>Looking at this, It's not hard to get lost in the jungle of monads :)<br>From my own experience (which isn't long), I think the most effective way of learning<br>is trying to write all definitions and instances by you're own, getting a feeling for what is
<br>really going on..<br><br>Hope that this will be of any help!<br><br><blockquote style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;" class="gmail_quote"> - why is there no liftSTM function?
</blockquote></div><div><br>Don't know about that, but someone else sure does..<br><br>Regards<br>/Joel<br></div></div><br>