简体   繁体   中英

does call with current continuation ignore its own continuation?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM