穷人并发,了解monad实例?

Poor mans concurrency, understanding the monad instance?

我 运行 通过 this 实现并发指南,但我在理解这个 monad 实例时遇到了问题:

data Action m = Atom (m (Action m)) | Fork (Action m) (Action m) | Stop

newtype C m a = C {apply :: (a -> Action m) -> Action m}

instance Monad (C m ) where
 m >>= f         = C $ \k -> apply m(\a -> apply (f a) k) --?
 return x        = C $ \k -> k x

我了解延续 monad 的基本用途,但我正在努力破译此声明中发生的事情?

看到 C m a 实际上只是一种计算——基于抽象 Action m 类型——a 以连续传递样式 [=15] 表示可能会有所帮助=],所以数据构造器 C 和相应的记录选择器 apply 只是句法上的废话。在没有它们且没有显式 monad 实例的情况下重写,您将获得以下等效代码。 (注意这里的类型Cnt只是只是一个continuation,不是continuation monad。Control.Monad.Trans.Cont中的continuation monad更像我的CPS类型.)

type Cnt m a = (a -> Action m)   -- a continuation, not a Cont monad
type CPS m a = Cnt m a -> Action m
bind :: CPS m a -> (a -> CPS m b) -> CPS m b
cps_a `bind` a_to_cps_b = \cont_b -> cps_a (\a -> a_to_cps_b a cont_b)

或更详细的:

cps_a `bind` a_to_cps_b =
  \cont_b -> cps_a (\a -> let cps_b = a_to_cps_b a in cps_b cont_b)

这是如何工作的?好吧,括号中的部分有一个自由变量 cont_b,它是一个 b-continuation;但是,给定这个延续,它只是一个 a-延续,它使用 a_to_cps_b 构造一个 b-计算(以 CPS 风格),它是适用于免费 cont_b 延续。简而言之,括号中的部分是包含在 a-continuation 中的提供的 a_to_cps_b。为了将它与 cps_a 结合起来,我们只需将 cps_a 应用于此 a-continuation,它表示 cps_a 表示的 a-计算与产生 b 计算的映射 a_to_cps_b,全部用 CPS 表示,带有一个自由变量 b_cont。对这个自由变量的抽象为我们提供了我们需要的 CPS m b

认为 这可能有助于使整个事情更容易理解,你现在可以回到原来的定义,认识到 \a -> apply (f a) k 确实是一个 a-f :: a -> C m b 的延续版本,用表示 b-延续的自由变量 k 表示。 apply m 可用于将 a-计算 m 应用到此 a-continuation,我们剩下的是结合 a-计算的东西m 与从 ab 计算的映射 f,全部以名为 k 的免费 b-延续表示,我们可以 lambda-abstract 构造绑定运算符应该 return 所需的 b-计算。