我正在浏览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的基本用法,但我正在努力破译这个声明中发生的事情?
答案 0 :(得分:4)
可能有助于看到C m a
实际上只是一个计算 - 在抽象的Action m
类型上 - 以a
表示的连续传递样式(a -> Action m) -> Action m
,因此数据构造函数C
和相应的记录选择器apply
只是语法上的粗糙。如果没有它们而没有显式的monad实例,则可以获得以下等效代码。 (请注意,此处类型Cnt
只是延续,而不是延续monad。Control.Monad.Trans.Cont
中的延续monad更像是我的CPS
类型。)< / p>
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
- 延续;但是,给出了这个延续,它只是一个a
- 继续,使用a_to_cps_b
来构造b
- 计算(CPS风格),应用于免费cont_b
延续。简而言之,括号中的部分是包含在a_to_cps_b
中的提供的a
- 延续。要将其与cps_a
结合使用,我们只需将cps_a
应用于此a
- 续,即代表a
- 由cps_a
表示的计算的组合产生a_to_cps_b
- 计算的地图b
,全部用CPS表示,带有自由变量b_cont
。对这个自由变量进行抽象可以得到我们需要的CPS m b
。
我认为可能有助于让整个事情更易于理解,现在您可以回到原始定义,并认识到\a -> apply (f a) k
确实是a
- f :: a -> C m b
的续展版本以表示k
- 续集的自由变量b
表示。 apply m
可用于将a
- 计算m
应用于此a
- 延续,我们留下了一些结合a
- 计算的东西m
地图f
从a
到b
- 计算,全部用免费b
表示 - 名为k
的续篇,我们可以lambda-abstract来构造所需的b
- 绑定运算符应该返回的计算。