Is there any difference between “MonadIO m” and “MonadBaseControl IO m”?

给你一囗甜甜゛ 提交于 2019-12-05 01:58:44

liftBase is part of MonadBase which is a generalization of MonadIO for any base monad and, as you said, MonadBase IO provides the same functionality as MonadIO.

However, MonadBaseControl is a bit more complicated beast. In MonadBaseControl IO m you have

liftBaseWith :: ((forall a. m a -> IO (StM m a)) -> IO a) -> m a
restoreM     :: StM m a -> m a

It's easiest to see what the practical uses are by looking at examples. For example, the bracket from basehas the signature

bracket ::  IO a -> (a -> IO b) -> (a -> IO c) -> IO c

With just MonadBase IO m (or MonadIO m) you can lift the main bracket invocation into m but the bracketing actions still need to be in plain old IO.

throw and catch are maybe even better examples:

throw :: Exception e => e -> a
catch :: Exception e => IO a -> (e -> IO a) -> IO a

You can easily thrown an exception from any MonadIO m and you can catch exception from IO a inside MonadIO m but again, both the action being run in catch and the exception handler itself need to be IO a not m a.

Now MonadBaseControl IO makes it possible to write bracket and catch in a way that allows the parameter actions to also be of type m a instead of being restricted to the base monad. The generic implementation for the above functions (as well as many others) can be found in the package lifted-base. For example:

catch   :: (MonadBaseControl IO m, Exception e) => m a -> (e -> m a) -> m a
bracket :: MonadBaseControl IO m => m a -> (a -> m b) -> (a -> m c) -> m c

EDIT: And now that I actually re-read your question properly...

No, I don't see any reason why the signature requires both MonadIO m and MonadBaseControl IO m since MonadBaseControl IO m should imply MonadBase IO m which enables the exact same functionality. So maybe it's just a left-over from some older version.

Looking at the source, it's probably just because runTCPClient calls sourceSocket and sinkSocket internally and those require MonadIO. I'm guessing that the reason why all the functions in the package don't simply use MonadBase IO is that MonadIO is more familiar to people and most monad transformers have a instance defined for MonadIO m => MonadIO (SomeT m) but users might have to write their own instance for MonadBase IO.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!