显然Concurrent a
相同Cont Action a
其中Cont
是延续单子。下面是延续一个简单的解释:
- 考虑函数
f :: a -> b
一些任意类型的a
和b
。我们想把这个函数转换成连续传递样式。我们如何做?
- 假设我们有一个延续
k :: b -> r
,它将返回值f
作为输入,并且它自己返回任意类型的值r
。在此之后,我们可以将f
转换为CPS。
- 让
g :: a -> (b -> r) -> r
成为f
的CPS版本函数。请注意,它需要一个附加参数(即继续k
)并返回应用于其输出b
的k
的结果。
让我们举一个实际的例子,其中f
是谓语功能odd :: Int -> Bool
:
odd :: Int -> Bool
odd n = n `mod` 2 == 1
这里是写在延续传递风格相同的功能:
odd' :: Int -> (Bool -> r) -> r
odd' n k = k (n `mod` 2 == 1)
的(Bool -> r) -> r
部分可以抽象出作为延续单子:
data Cont r a = Cont { runCont :: (a -> r) -> r }
odd' :: Int -> Cont r Bool
odd' n = return (n `mod` 2 == 1)
instance Monad (Cont r) where
return a = Cont (\k -> k a)
m >>= f = Cont (\k -> runCont m (\a -> runCont (f a) k))
请注意,对于某些任意类型r
,延续k
的类型为Bool -> r
。因此,延续k
可以是以Bool
作为参数的任何函数。例如:
cont :: Bool -> IO()
cont = print
main :: IO()
main = odd' 21 cont
然而,在Concurrent
的情况下,这是r
不是任意的。它专门用于Action
。事实上,我们可以定义Concurrent
作为一种代名词Cont Action
如下:
type Concurrent = Cont Action
现在,我们并不需要实现Monad
实例Concurrent
,因为它是与上述定义相同Monad
实例Cont r
。
runConcurrent :: Concurrent a -> ContinuationPseudoMonad a
runConcurrent (Concurrent g) = g
instance Monad Concurrent where
return a = Concurrent (\k -> k a)
m >>= f = Concurrent (\k -> runConcurrent m (\a -> runConcurrent (f a) k))
注意无处在instance Monad Concurrent
定义有我们利用了Action
。这是因为Concurrent = Cont Action
和Cont r
的monad实例透明地使用r
。
你的问题是如何定义'Concurrent'的'return'和'>> =',就像你上面定义的那样? – rampion
此外,轻微的错字 - 我认为你的意思是'数据Concurrent a = Concurrent(ContinuationPseudoMonad a)',因为'数据Concurrent a = Concurrent ContinuationPseudoMonad a'是一个错误。 – rampion
我已根据您的说法进行了相应更正。事情是我没有成功掌握什么是“继续 - >行动”。这个抽象的名字会很棒。 –