有没有办法捕获符号中的延续?

时间:2012-07-05 20:49:03

标签: haskell types continuations coroutine continuation-passing

由于以下是阻止:

do
  x <- foo
  y <- bar
  return x + y

是以下形式:

foo >>= (\x -> bar >>= (\y -> return x + y))

这里不是\x -> ...y -> ...实际延续吗?

我想知道是否有一种方法可以捕获bind定义中的延续,但我无法确定正确的类型。即:

data Pause a = Pause a | Stop

instance Monad Pause where
  return x = Stop
  m >>= k = Pause k         -- this doesn't work of course

现在我尝试使用以下类型进行混淆:

data Pause a = Pause a (a -> Pause ???) | Stop
                       ------- k ------

但这也不起作用。有没有办法捕捉这些隐含的延续?

是的,我知道Cont monad,我只是在试验和尝试。

2 个答案:

答案 0 :(得分:1)

好的,我不太确定,但让我提出一些想法。我不太确定它是什么 应该意味着抓住延续。例如,你可以捕获整体 do在结构中阻止:

{-# LANGUAGE ExistentialQuantification #-}

import Control.Monad

data MonadExp b = Return b | forall a. Bind (MonadExp a) (a -> MonadExp b)

instance Monad MonadExp where
    return x = Return x
    f >>= g = Bind f g

例如:

block :: MonadExp Int
block = do
    x <- return 1
    y <- return 2
    return $ x + y

instance Show (MonadExp a) where
    show (Return _) = "Return _"
    show (Bind _ _) = "Bind _ _"

print block
>> Bind _ _

然后评估整个事情:

finish :: MonadExp a -> a
finish (Return x) = x
finish (Bind f g) = finish $ g (finish f)

print $ finish block
>> 3

或者单步执行并查看部分

step :: MonadExp a -> MonadExp a
step (Return _) = error "At the end"
step (Bind f g) = g $ finish f

print $ step block
>> Bind _ _
print $ step $ step block
>> Return _

嗯,现在我想的更多,那可能不是你要问的。但 也许它会帮助你思考。

答案 1 :(得分:1)

好吧,我不知道你的lambdas是否是最严格意义上的延续,但它们在我看来也与这个概念类似。

但是请注意,如果它们是延续的话,那么脱落的monadic代码已经用连续传递方式(CPS)编写了。 “捕获”延续的控制操作员的通常概念是基于直接式程序; “捕获”延续仅隐含在直接式程序中,但CPS转换使其明确。

由于desadared monadic代码已经在CPS或类似的东西,好吧,也许一种解决问题的方法是monadic代码是否可以表达CPS代码可以表达的一些控制流技巧。通常情况下,这些技巧归结为这样的想法,即在CPS制度下,通过调用其延续来完成一个函数是常规的,一个函数可以选择替换它的继续与另一个选择。这个替换延续可以通过引用原始延续来构造,以便它可以反过来“恢复”原始延续,如果它选择的话。因此,例如,协同程序被实现为相互“替换/恢复”循环。

从这个角度来看,我认为你的答案基本上没有; CPS要求在foo >>= bar中,foo必须能够选择是否会调用barfoo必须能够替代bar但是,(>>=)本身并不提供foo执行此操作的机制,更重要的是,(>>=)控制着执行流程,而不是foo。一些特定的monad实现部分或全部(例如,Maybe monad允许foo通过生成bar结果而放弃Nothing的执行,但其他人不要吨。

我能得到的最近的就是放弃(>>=)并改为使用它:

-- | Execute action @foo@ with its "continuation" @bar@.
callCC :: Monad m => ((a -> m b) -> m b) -> (a -> m b) -> m b
foo `callCC` bar = foo bar

此处foo可以选择是否会使用bar。但请注意,此callCC实际上只是($)