用当前的继续调用会忽略它自己的延续吗?

时间:2016-07-24 12:28:21

标签: haskell functional-programming continuations

我试图了解继续传递和Call-with-current-continuation。 根据此页面: https://en.wikipedia.org/wiki/Monad_(functional_programming)#Continuation_monad 使用CC方法的调用实现如下:

call_cc :: ((a -> (b -> r) -> r) -> (a -> r) -> r) -> (a -> r) -> r
call_cc f k = f (\t x -> k t) k

正如此signatureimplementation所述。

但是,我们可以看到此处x参数从未使用过。 这是否意味着始终忽略传递给f的任何延续,因为初始延续k总是替换它? 在这种情况下,它是否意味着call-with-cc只能调用一个深度而不是更多的函数? (因为将忽略在具有延续x的正常控制流中调用的下一个函数)

在这种情况下,它似乎非常有限,它的实际用途是什么?

2 个答案:

答案 0 :(得分:1)

Here您可以找到更具可读性的callCC定义,并提供非常具体的解释:

class (Monad m) => MonadCont m where 
    callCC :: ((a -> m b) -> m a) -> m a 
  

MonadCont类提供callCC函数,它提供了一个   与Continuation monads一起使用的escape continuation机制。逃逸   continuation允许您中止当前计算并返回a   价值立即。它们实现了与throwError和类似的效果   错误monad中的catchError。

Here你可以看到一些很好的例子如何使用它。

但总的来说:callCC不会忽略输入,但它会增强您的程序。

您正在定义一些功能,如

doSomething panicExit = do
  ...
  when failCondition $ panicExit inputToStartOver
  ...

然后通过callCC doSomething

转换为正常延续

正是这个panicExit输入忽略抛出一样引起了你的注意。您的程序没有义务失败到默认值,但您可以在需要时执行此操作。

答案 1 :(得分:1)

(为了说明,让我使用更简洁的语法而不是真正的Haskell。)

callcc f将给定函数f应用于当前延续k如果在另一个延续k下调用此延续x,则后一个继续x确实被丢弃

例如,在1 + callcc (\k -> 2 + (k 3))中,变量k绑定到外部延续1 + [],其中[] hole ,其中a返回值应填写。如果在k中应用此(k 3),则内部延续1 + (2 + [])将被丢弃。因此,整个表达式变为1 + 3并计算为4

另一方面,在1 + callcc (\k -> 2 + 4)中,永远不会调用延续k,整个表达式会产生1 + (2 + 4),即7

通过结合上述两个示例,您可以执行更复杂的操作,例如1 + callcc (\k -> 2 + (if some_complex_condition then (k 3) else 4)),如果1 + 3some_complex_condition,则为true,否则为1 + (2 + 4)

总结并回答你的问题:

  

但是,我们可以看到x参数从未使用过。

如果调用延续x

k将被丢弃;但是,当k 被调用时,x将应用于"正常"返回值,如上例所示。 (后一种情况对应于continuation monad中的return操作。)

P.S。

上面我采用了直接的非monadic语法来简洁起见。在Haskell中使用continuation monad,以下示例

callCC (\k -> do r <- (k 3); return (2 + r))

调用外部延续k 丢弃内部2 + [] 并返回3,而

callCC (\k -> do r <- (return 4); return (2 + r))

给出2 + 4