在 monad 实例声明中使用 monad 超类?

Use of a monad superclass in a monad instance declaration?

我正在使用以下数据类型实现一个非常简单的穷人并发结构:

data C m a = Atomic (m (C m a)) | Done a

我正在为此创建一个 monad 实例:

instance Monad m => Monad (C m) where
  (>>=) (Atomic m) f      = Atomic $ (liftM (>>= f) m)
  (>>=) (Done v) f        = f v
  return                  = Done

Q1。我说 Atomic $ (liftM (>>= f) m) 正在创建一个新的 Atomic monad 是否正确,其中包含应用于 m 内部值的 f (* -> *) 的结果?

Q2。我说这里使用 superclass Monad m 来启用 liftM 是否正确?如果是这样,因为这是 Monad class 的一个实例,为什么不能直接访问 liftM

Q1。它正在创造 Atomic 价值 。 Monad 是类型级别的映射。由于 fC m a>>= 的第二个参数,我们知道它的类型

f :: Monad m => a -> C m b

因此

(>>= f) :: Monad m => C m a -> C m b

f 扩展以展开其参数,并且

liftM (>>= f) :: (Monad m1, Monad m) => m1 (C m a) -> m1 (C m b)

只是简单地提升转换为m1,在你的设置中与m统一。当您从 Atomic 中提取值 m 并将其传递给 liftM 时,您使用 monad m 的绑定(通过 liftM)来提取内部 C m a 传递给 fliftM 定义的第二部分将结果重新包装为 m (C m b),您将其包装在 Atomic 中。所以是的。

Q2。是的。但它是底层 monad mliftMC m aliftM 是根据实例定义的(它的 >>=return)。通过使用 C m aliftM(如果您设法根据 liftM 定义 >>=),您将得到一个循环定义。您需要约束 Monad m 来为 m (C m a) 创建管道以穿过 >>=f。事实上,正如 Benjamin Hodgson 所指出的,Monad m 是一个不必要的强约束,Functor m 就足够了。 C 实际上是 Free together with the relevant implementations 这一事实提供了对此事最深入的了解。