“MonadIO m”是否有区别?和“MonadBaseControl IO m”? [英] Is there any difference between "MonadIO m" and "MonadBaseControl IO m"?

查看:133
本文介绍了“MonadIO m”是否有区别?和“MonadBaseControl IO m”?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

功能 runTCPClient network-conduit 有以下签名:

  runTCPClient ::(MonadIO m ,MonadBaseControl IO m)
=> ClientSettings m - >应用程序m - > m()

MonadIO m p>

  liftIO :: IO a  - > ma 

MonadBaseControl IO m p>

  liftBase :: IO a  - > m a 

没有明显区别。他们是否提供相同的功能?如果是,为什么类型签名中的重复?如果没有,有什么区别?

解决方案

liftBase a href =http://hackage.haskell.org/package/transformers-base-0.4.1/docs/Control-Monad-Base.html#t:MonadBase =noreferrer> MonadBase ,这是对任何基本monad的 MonadIO 的推广,如您所说, MonadBase IO 提供了与 MonadIO



相同的功能。但是, MonadBaseControl 是一个更复杂的野兽。在 MonadBaseControl IO m 中,您有

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

通过查看示例可以很容易地看到实际用途。例如, b


$ > 括号:: IO a - > (a→IO b)→> (a→IOc)→> IO c

MonadBase IO m (或 MonadIO m ),您可以将主括号调用提升为 m 但括起动作仍然需要简单的旧 IO



throw 和 catch 可能是更好的例子:

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

您可以轻松地从任何 MonadIO m ,你可以从 IO a MonadIO m 内捕获异常,但同样, catch ,异常处理程序本身必须是 IO a 不是 ma
现在 MonadBaseControl IO 可以写括号 catch 以允许参数操作也可以是类型 ma 而不是限制为基地monad。上述功能(以及其他功能)的通用实现可以在包
解除基 。例如:

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

编辑:现在我可以正确地重新读取您的问题...

不,我没有看到签名要求 MonadIO m MonadBaseControl IO m MonadBaseControl IO m 应该暗示 MonadBase IO m which启用完全相同的功能。所以也许这只是一些旧版本的遗留问题。



查看源代码,可能仅仅是因为 runTCPClient 在内部调用 sourceSocket sinkSocket 并且需要 MonadIO 。我猜测,包中所有函数不会简单地使用 MonadBase IO 的原因是 MonadIO 对于人们来说更为熟悉,大多数单变换器都有一个为> MonadIO m =>定义的实例。 MonadIO(SomeT m)但用户可能必须为 MonadBase IO 写入自己的实例。


Function runTCPClient from network-conduit has the following signature:

runTCPClient :: (MonadIO m, MonadBaseControl IO m)
             => ClientSettings m -> Application m -> m ()

MonadIO m provides

liftIO :: IO a -> m a

and MonadBaseControl IO m provides

liftBase :: IO a -> m a

There is no visible difference. Do they provide the same functionality? If yes, why the duplication in the type signature? If not, what's the difference?

解决方案

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.

这篇关于“MonadIO m”是否有区别?和“MonadBaseControl IO m”?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆