
On 8/11/06, Stefan Aeschbacher
I'm trying to understand Monad Transformers. The code below works as expected but I have the following questions: I'll take a shot.
- why can I use liftIO but not lift in the doSomething function? I fooled around a bit, and the answer I came up with is that lift is only able to lift through the first transformer, while liftIO is able to lift through them both. You'd need to use something like (lift . lift).
The difference is in what the parameters to the classes MonadTrans and MonadIO represent. MonadIO m means that m is a monad into which IO-actions can be lifted. MonadTrans t means that (t m) is a monad into which m-actions can be lifted. However, since the type class doesn't know about m, it's impossible to exprss that composition of two transformers is itself a transformer, whereas you can easily declare that the result of transforming a MonadIO with a certain transformer results in a MonadIO. It's not immediately clear to me how to express that composition of transformers results in a transformer even with multi-parameter type classes, but I'm not a type-hacking guru. I wouldn't be surprised if it's possible.
- why is there no liftSTM function? Because there is no MonadSTM typeclass specifying which monads can have STM actions properly lifted into them. You could write your own. here's a first pass:
class Monad m => MonadSTM m where liftSTM :: STM a -> m a instance MonadSTM STM where liftSTM = id instance (MonadSTM m) => MonadSTM (ReaderT m) where liftSTM = lift . liftSTM instance (MonadSTM m) => MonadSTM (WriterT m) where liftSTM = lift . liftSTM Et cetera... However, I have no idea if there were reasons why such a class was not included other than simple oversight. It's possible that lifting like the above may not work like you'd expect, and perhaps it's difficult to make it do so. But, if you're willing to be a guinea pig, go ahead and try those out. :) Enjoy. -- Dan