Haskell: lift vs liftIO

后端 未结 3 1274
滥情空心
滥情空心 2021-01-30 05:03

In what situations should liftIO be used? When I\'m using ErrorT String IO, the lift function works to lift IO actions into ErrorT

3条回答
  •  醉话见心
    2021-01-30 05:21

    Previous answers all explain the difference quite well. I just wanted to shed a some light on the inner workings so that it could be easier to understand how liftIO isn't something magical (for the novice Haskellers like me).

    liftIO :: IO a -> m a
    

    is a wise tool just build upon

    lift :: (Control.Monad.Trans.Class.MonadTrans t, Monad m) => m a -> t m a
    

    and most often used when the bottom monad is IO. For the IO monad it's definition is quite simple.

    class (Monad m) => MonadIO m where
      liftIO :: IO a -> m a
    
    instance MonadIO IO where
      liftIO = id
    

    That simple... liftIO is in fact just id for the IO monad and basically IO is the only one that comes within the definition of the type class.

    The thing is, when we have a monad type which is composed of several layers of monad transformers over IO, we better have an MonadIO instance for each one of those monad transformer layers. For example the MonadIO instance of MaybeT m requires m to be of MonadIO typeclass as well.

    Writing a MonadIO instance is basically a very simple task too. For MaybeT m it is defined like

    instance (MonadIO m) => MonadIO (MaybeT m) where
      liftIO = lift . liftIO
    

    or for StateT s m

    instance (MonadIO m) => MonadIO (StateT s m) where
      liftIO = lift . liftIO
    

    they are all the same. Imagine when you have a 4 layer transformer stack then you either need to do lift . lift . lift . lift $ myIOAction or just liftIO myIOAction. If you think about it, every lift . liftIO will take you one layer down in the stack up until it digs all the way down to IO at where liftIO is defined as id and finalizes with the same code like composed lifts above.

    So this is basically why regardless of the transformer stack configuration, provided that all underlaying layers are members of MonadIO and MonadTrans a single liftIO is just fine.

提交回复
热议问题