【问题标题】:Why does `hoist` constrain the type parameter of this monad?为什么`hoist`约束这个monad的类型参数?
【发布时间】:2013-08-28 12:05:07
【问题描述】:

我有一些组成两个单子的函数:

comp :: Monad m => m a -> m b -> m b

还有两个这样的 monad 实例,其中 on 是“内部”Mfunctor

ms :: Monad m => m String
ms = undefined

tma :: (Monad m, MFunctor t) => t m a
tma = undefined

现在如果我尝试用tma 组合ms

tmas = hoist (\ma -> comp ma ms) tma

我收到此错误:

 Could not deduce (a ~ [Char])
    from the context (Monad m, MFunctor t)
      bound by the inferred type of
               comp :: (Monad m, MFunctor t) => t m b
      at Coroutine.hs:607:1-40
      `a' is a rigid type variable bound by
          a type expected by the context: m a -> m a at Coroutine.hs:607:8
    Expected type: m a
      Actual type: m String

其中指出ms 中的a 必须是任意类型:ms :: Monad m => m a

为什么会这样,有没有办法用特定参数的单子组合tma

我可以看到葫芦的签名是:

hoist :: (Monad m, MFunctor t) => (forall a. m a -> n a) -> t m b -> t n b

但无法想象forall 如何影响我正在尝试做的事情,如果它有任何影响的话。

【问题讨论】:

    标签: haskell monads


    【解决方案1】:

    将参数的顺序切换为comp,如下所示:

    tmas = hoist (\ma -> comp ms ma) tma
    
    -- or more simply:
    tmas = hoist (comp ms) tma
    

    原因是comp的类型是:

    comp :: (Monad m) => m a -> m b -> m b
    

    如果您将ms 设置为第二个参数,则b 类型检查为String,您会得到:

    (`comp` ms) :: (Monad m) => m a -> m String
    

    ...但是如果您将ms 设置为第一个参数,则a 类型检查为String,您会得到:

    (ms `comp`) :: (Monad m) => m b -> m b
    

    后一种类型是 hoist 的正确类型,因为 b 是普遍量化的(即“forall”)。

    要回答您关于正确性的问题,答案是通用量化保证 hoist 的参数仅修改 monad 层而不修改 monad 返回值。但是,如果您也打算修改返回值,那么 hoist 不是您想要的。

    【讨论】:

      【解决方案2】:

      hoist 的类型表示它需要一个函数(forall a. m a -> n a),即一个改变“容器”类型但保持类型参数相同的函数。这里的forall 表示你提供的函数不能专门用于任何特定的a,但必须适用于任何类型参数。

      您尝试使用的函数 (\ma -> comp ma ms) 的类型为 m a -> m String,因此它与 hoist 所期望的几乎相反,因为它使容器 (m) 保持不变但更改了类型参数(从aString)。

      我认为在这种情况下,您实际上正在寻找的不是hoist,而是一个提升单子函数以处理转换后的单子的函数,因此您需要的不是MFunctor,而是:

      import Control.Monad.Trans.Class
      
      tmas :: (Monad m, Monad (t m), MonadTrans t) => t m String
      tmas = transLift (\ma -> comp ma ms) tma
      
      transLift :: (Monad m, Monad (t m), MonadTrans t) => (m a -> m b) -> t m a -> t m b
      transLift f tma = tma >>= lift . f . return
      

      【讨论】:

      • 感谢您的解释。 forall 的存在是否能以某种方式保证某种程度的正确性?
      猜你喜欢
      • 1970-01-01
      • 2017-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-13
      • 2012-09-22
      • 2015-11-01
      • 1970-01-01
      相关资源
      最近更新 更多