“MonadIO m”是否有区别?和“MonadBaseControl IO m”? [英] Is there any difference between "MonadIO m" and "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
通过查看示例可以很容易地看到实际用途。例如, MonadBase IO m b
(或
$
> 括号:: IO a - > (a→IO b)→> (a→IOc)→> IO c
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 $ c $
现在 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 base
has 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屋!