如何定义一个由两个任意单子变换器组成的单子变换器?

How do define a monad transformer that is the composition of two arbitrary monad transformers?

我想写类似下面的东西:

newtype FooT c d m a = FooT { unFooT :: (c (d m)) a }

instance (MonadTrans c, MonadTrans d) => MonadTrans (FooT c d) where
  lift = FooT . lift . lift

但是,此代码段无法编译:

Could not deduce (Monad (d m)) arising from a use of ‘lift’

我明白为什么这不会编译;我们不知道任意转换器 d m 的应用本身就是一个 monad。但是,我不确定继续进行的最佳方式。 有没有一种干净的方法可以使这样的工作起作用?如果我可以沿着 Monad (d m) 行向实例声明的左侧添加一个约束,大概它会通过,但我不知道该怎么做,因为 m 不是绑定。

使用 QuantifiedConstraints GHC 扩展,这是

{-# LANGUAGE QuantifiedConstraints #-}

instance (MonadTrans c, MonadTrans d, forall m. Monad m => Monad (d m)) =>
         MonadTrans (FooT c d) where
  lift = FooT . lift . lift
约束中的

mlift 中的 m 不同。量化约束只是意味着它所说的(“对于任何 m :: Type -> Type,如果 Monad m 需要 Monad (d m)”),并且在 lift 中,通用语句正在用特定的 m 作为参数传递给 lift。因此 liftm 没有超出其范围。

transformers 0.6 the MonadTrans type class has had a requirement that it preserves Monad.

这意味着MonadTrans的定义是:

type Lifting cls trans = forall m. cls m => cls (trans m)

class Lifting Monad trans => MonadTrans trans where
  lift :: Monad m => m ~> trans m

你称之为FooT的变形金刚组合(ComposeT)不需要指定提升,所以你在问题中提供的代码应该适用于版本0.6+.

ComposeT already exists in deriving-trans

newtype Ok m a = Ok (Int -> Bool -> m a)
  deriving
    ( Functor, Applicative, Alternative, Contravariant
    , Monad, MonadPlus, MonadCont, MonadIO, MonadFix,
    , MonadFail, MonadZip
    )
  via ReaderT Int (ReaderT Bool m)

  deriving MonadTrans
  via ComposeT (ReaderT Int) (ReaderT Bool)