我试图了解继续传递和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
正如此signature和implementation所述。
但是,我们可以看到此处x
参数从未使用过。
这是否意味着始终忽略传递给f
的任何延续,因为初始延续k
总是替换它?
在这种情况下,它是否意味着call-with-cc
只能调用一个深度而不是更多的函数? (因为将忽略在具有延续x
的正常控制流中调用的下一个函数)
在这种情况下,它似乎非常有限,它的实际用途是什么?
答案 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 + 3
为some_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
。