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

时间:2017-03-16 09:30:27

标签: haskell monads lifting

我实现了一个非常简单的穷人并发结构,具有以下数据类型:

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,其中包含应用于f内部值* -> *m)的结果?< / p>

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

1 个答案:

答案 0 :(得分:4)

Q1。它正在创建Atomic 。 Monad是类型级别的映射。由于f>>= C 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统一。当您从m中提取值Atomic并将其传递给liftM时,您可以使用monad m的绑定(通过liftM)来提取要传递给C m a的内部fliftM定义的第二部分将结果重新包装为m (C m b),并将其包含在Atomic中。是的。

Q2。是。但它是潜在monad liftM的{​​{1}}。 m的{​​{1}}是根据实例(liftMC m a)定义的。使用>>=&#39; return(如果您设法根据C m a定义liftM),您将获得循环定义。您需要约束>>=来创建liftM的管道,以便遍历Monad mm (C m a)。事实上正如本杰明霍奇森指出的那样,>>=是一个不必要的强大的遗体,f就足够了。 Monad m实际上Free与相关implementations一起提供了最明显的事实。