I'm trying to understand continuation passing and Call-with-current-continuation. As per this page: https://en.wikipedia.org/wiki/Monad_(functional_programming)#Continuation_monad the call with CC method is implemented as follows:
call_cc :: ((a -> (b -> r) -> r) -> (a -> r) -> r) -> (a -> r) -> r
call_cc f k = f (\t x -> k t) k
As described by this signature and implementation .
However, we can see that the x
parameter is here never used. Does it mean that any continuation passed to f
is always ignored that the initial continuation k
is always replacing it? In that case, does it mean that call-with-cc
can only ever call a function with that is one-level deep and not more? (because the next function that would be called in a normal control flow with a continuation x
is ignored)
In that case it seems very limiting, what is its practical use?
Here you can find more readable definition of callCC
with very specific explanation:
class (Monad m) => MonadCont m where
callCC :: ((a -> m b) -> m a) -> m a
The MonadCont class provides the callCC function, which provides an escape continuation mechanism for use with Continuation monads. Escape continuations allow you to abort the current computation and return a value immediately. They achieve a similar effect to throwError and catchError within an Error monad.
Here you can see some pretty examples how to use it.
But in general: callCC
does not ignore input, but it enhances your procedure with way to do it.
You are defining some function like
doSomething panicExit = do
...
when failCondition $ panicExit inputToStartOver
...
And then converting to normal continuation via callCC doSomething
And exactly this panicExit
input-ignoring throw-like has caught your eye. You procedure is not obliged to fail to default value, but you can do it when you like.
(For the sake of exposition, let me use more concise syntax rather than real Haskell.)
callcc f
applies the given function f
to the current continuation k
. If this continuation k
is ever invoked under another continuation x
, the latter continuation x
is indeed discarded .
For instance, in 1 + callcc (\\k -> 2 + (k 3))
, the variable k
is bound to the outer continuation 1 + []
where []
is a hole into which a return value shall be filled. When this k
is applied as in (k 3)
, the inner continuation 1 + (2 + [])
is discarded . As a result, the entire expression becomes 1 + 3
and evaluates to 4
.
On the other hand, in 1 + callcc (\\k -> 2 + 4)
, the continuation k
is never invoked and the whole expression yields 1 + (2 + 4)
, that is, 7
.
By combining the two examples above, you can do more complicated things like 1 + callcc (\\k -> 2 + (if some_complex_condition then (k 3) else 4))
, which gives 1 + 3
if some_complex_condition
is true
, or 1 + (2 + 4)
otherwise.
To sum up and answer your question:
However, we can see that the x parameter is here never used.
x
is discarded if the continuation k
is invoked ; however, when k
is not invoked, x
is applied to the "normal" return value, as in the examples above. (The latter case corresponds to the return
operation in the continuation monad.)
PS
Above I adopted a direct, non-monadic syntax for brevity. Using the continuation monad in Haskell, the following example
callCC (\k -> do r <- (k 3); return (2 + r))
invokes the outer continuation k
discarding the inner 2 + []
and returns 3
, while
callCC (\k -> do r <- (return 4); return (2 + r))
gives 2 + 4
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.