"MonadIO m"和"MonadBaseControl IO m"有什么区别吗?

 fuxw 发布于 2023-02-06 14:51

来自network-conduit的函数runTCPClient具有以下签名:

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

MonadIO m 提供

liftIO :: IO a -> m a

MonadBaseControl IO m提供

liftBase :: IO a -> m a

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

1 个回答
  • liftBaseMonadBase其中一部分是MonadIO对任何基础monad 的推广,正如你所说,MonadBase IO它提供了相同的功能MonadIO.

    但是,MonadBaseControl野兽有点复杂.在MonadBaseControl IO m你有

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

    通过查看示例,最容易看到实际用途.例如,bracketfrom base具有签名

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

    只需MonadBase IO m(或MonadIO m)您可以将主要bracket调用解除,m但包围操作仍然需要保持原状IO.

    throw并且catch是甚至更好的例子:

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

    您可以轻松地从任何内容抛出异常MonadIO m,您可以从IO a内部捕获异常,MonadIO m但同样,运行的操作catch和异常处理程序本身IO a都不需要m a.

    现在MonadBaseControl IO可以以允许参数动作也是类型的方式进行编写bracket,而不是限制为基本monad.可以在包中找到上述函数(以及许多其他函数)的通用实现.例如:catchm alifted-base

    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
    

    编辑:现在我实际上正确地重新阅读了你的问题......

    不,我没有看到任何理由为什么签名需要两者MonadIO m,MonadBaseControl IO m因为MonadBaseControl IO m应该暗示MonadBase IO m哪些能够实现完全相同的功能.所以也许它只是一些旧版本的遗留物.

    看看来源,可能只是因为runTCPClient电话sourceSocketsinkSocket内部以及那些要求MonadIO.我猜测包中的所有函数不能简单使用MonadBase IO的原因MonadIO是人们更熟悉,大多数monad变换器都有一个实例定义,MonadIO m => MonadIO (SomeT m)但是用户可能必须编写自己的实例MonadBase IO.

    2023-02-06 14:55 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有