我实现了一个非常简单的穷人并发结构,具有以下数据类型:
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
?
答案 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
的内部f
。 liftM
定义的第二部分将结果重新包装为m (C m b)
,并将其包含在Atomic
中。是的。
Q2。是。但它是潜在monad liftM
的{{1}}。 m
的{{1}}是根据实例(liftM
和C m a
)定义的。使用>>=
&#39; return
(如果您设法根据C m a
定义liftM
),您将获得循环定义。您需要约束>>=
来创建liftM
的管道,以便遍历Monad m
和m (C m a)
。事实上正如本杰明霍奇森指出的那样,>>=
是一个不必要的强大的遗体,f
就足够了。 Monad m
实际上Free
与相关implementations一起提供了最明显的事实。