像 lift 这样的多态函数的类型约束

Type constraints for polymorphic functions like lift

所以我有这个代码

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import MonadA

data A = A

newtype MonadA a => MyStateT a b { runMyStateT :: StateT A a b }
    deriving (Functor, Applicative, Monad, MonadIO, MonadState A)

instance MonadTrans MyStateT where
    lift = MyStateT . lift

编译器抱怨它无法证明 lift 签名中的 mMonadA 类型,或者这就是我阅读这些神秘错误消息的方式。

Could not deduce (MonadA m) arising from a use of `MyStateT'
from the context (Monad m)
  bound by the type signature for
             lift :: Monad m => m a -> MyStateT m a

有办法解决这个问题吗?我想我需要约束才能实例化如下:

instance MonadA a => MonadA (MyStateT a) where
    f = MyStateT . lift . f

f 的这种实现是否也有效? (由于上述错误,我没有走那么远)。我希望右侧的 f 在内部 monad a.

上解析为 f

编辑:它确实有助于删除 newtype MonadA a => MyStateT ... 中的类型约束以避免我提到的确切错误。然而,还有另一个错误,我之前将其归因于同一件事,请考虑上面示例代码的延续(某些部分重复,现在没有类型限制):

class MonadB m where
    fB :: m ()

newtype MyStateT m a = MyStateT { runMyStateT :: StateT A m a}
    deriving (... MonadState A ...)

instance MonadTrans MyStateT where
    lift = MyStateT . lift

instance MonadA a => MonadA (MyStateT a) where
    f = lift . f

instance MonadA a => MonadB (MyStateT a) where
    fB = lift (modify (...))

错误是

Could not deduce (a ~ StateT A m0) from context (MonadA (MyStateT a), MonadA a)

在执行fB。早些时候我尝试 class MonadA m => MonadB m 无济于事。将 aStateT A m 匹配甚至没有意义。由于 MyStateTMonadState A 的一个实例,它应该可以工作,不是吗?

编辑:

好的,成功了:

fB = MyStateT (modify ...)

愚蠢的我。

解决方案是从 MyStateT 定义中删除约束:

newtype MyStateT a b { runMyStateT :: StateT A a b }
    deriving (Functor, Applicative, Monad, MonadIO, MonadState A)

数据类型约束基本上是无用的,因为您无论如何都需要将它们放在函数签名中。因此,该功能实际上是 deprecated.

I think I need the constraint to be able to instantiate as follows:

不是真的; instance MonadA a => MonadA (MyStateT a) 没有它也能正常工作。

Also would such an implementation of f work?

会的。请注意,当您为 MyStateT 提供了一个 MonadTrans 实例时,您实际上不需要明确地用 MyStateT 包装:

instance MonadA a => MonadA (MyStateT a) where
    f = lift . f