有没有办法用 monad 类型变量多态地提升 class 的实例,而不重叠实例?

Is there a way to polymorphically lift instances of a class with a monad type variable, without overlapping instances?

这个问题可以被认为是

的后续问题

其中提供了一个应用程序示例。

想法是类型类

class (Monad m) => Class m a where
  method :: a -> m ()

存在,基础实例在不同的 monads 中

instance Class M A where 
  method = undefined

instance Class (T M) B where
  method = undefined

。我想要的是一种将任何实例提升到自身或转换器堆栈中更高层的方法,就像 liftIOIO 所做的一样。我最初的想法是定义一个提升实例

instance (MonadTrans t, Class m a) => Class (t m) a where
  method = lift . method 

然而,当应用多个转换器时,这会产生重叠实例的问题,因为 lift 是多态的,并且可以替换为例如 lift . lift.

建议改为使用类似的默认实例,

class (Monad m) => Class m a where
  method :: a -> m ()
  default method :: (m ~ t n, MonadTrans t, Class n a) => a -> m ()
  method = lift . method

然后可用于声明提升实例

instance (MonadTrans t) => Class (t M) A

instance (MonadTrans t) => Class (t (T M)) B

。这可行,但是需要为每个基本实例声明提升实例,所以我很好奇;有没有其他方法可以解决这个问题而不求助于重叠实例?

你写

instance (MonadTrans t) => Class (t M) A
instance (MonadTrans t) => Class (t (T M)) B

This works, but lifting instances need to be declared for each base instance[....]

这不是这些默认值的用途。这些实例应该看起来像

instance Class m a => Class (StateT s m) a
instance Class m a => Class (MaybeT m) a

等等。