如何定义一个单子变压器,即两个任意单子变压器的组成?

发布于 2025-01-22 12:00:32 字数 478 浏览 2 评论 0原文

我想写一些类似于以下内容的内容:

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(dm)的行添加一个约束在实例声明的左侧,但是我不知道该怎么做,因为<代码> m 不绑定。

I want to write something similar to the following:

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

However, this snippet will not compile:

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

I understand why this won't compile; we don't know that the application of an arbitrary transformer d m is itself a monad. However, I'm not sure of the best way to proceed.
Is there a clean way to make something like this work? Presumably it would go through if I could add a constraint along the lines of Monad (d m) to the left-hand-side of the instance declaration, but I don't know how to do so since m is not bound.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

满身野味 2025-01-29 12:00:32

使用endenifiedConstraints GHC扩展程序,这是

{-# LANGUAGE QuantifiedConstraints #-}

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

约束中的mm中的m不像lift中的m。量化的约束仅表示它说的内容(“对于任何m :: type - &gt; type,如果monad m requient requiend monad(dm)> ”),在lift中,正在与特定m作为参数传递给lift的特定m实例化。因此,提升's m不会逃脱其范围。

With the QuantifiedConstraints GHC extension, this is

{-# LANGUAGE QuantifiedConstraints #-}

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

m in the constraint is not the same m as in lift. The quantified constraint simply means what it says ("for any m :: Type -> Type, if Monad m require Monad (d m)"), and in lift that universal statement is being instantiated with the particular m being passed as argument to lift. Thus lift's m does not escape its scope.

陌生 2025-01-29 12:00:32

因为 promensioners 0.6 monadtrans 类型类有一个要求它可以保留它

这意味着 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

变形金刚的组成(composet),您调用foot不需要指定提升,因此代码代码您的问题中提供的版本应适用于 0.6+

已经存在于 derving-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)

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

This means the definition of MonadTrans is:

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

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

The composition of transformers (ComposeT), which you call FooT doesn't need to specify the lifting, so the code you supplied in your question should work for versions 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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文