X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=blobdiff_plain;f=cps_and_continuation_operators.mdwn;h=aa2900c8b0012b553ff6e705ace9c6041b40892b;hp=df27db76bb7955caee494849cd3c03385ea253e2;hb=333924dc64733882d990c740fba395ae87185ad8;hpb=be655939804c17330069657c3f59c4beec0704b5 diff --git a/cps_and_continuation_operators.mdwn b/cps_and_continuation_operators.mdwn index df27db76..aa2900c8 100644 --- a/cps_and_continuation_operators.mdwn +++ b/cps_and_continuation_operators.mdwn @@ -283,7 +283,7 @@ Here are a series of examples from *The Seasoned Schemer*, which we recommended For reminders about Scheme syntax, see [here](/assignment8/) and [here](/week1/) and [here](/translating_between_ocaml_scheme_and_haskell). Other resources are on our [[Learning Scheme]] page. -All of the examples assume the following preface: +Most of the examples assume the following preface: #lang racket @@ -330,13 +330,14 @@ Next, try to figure out what this function does: [(null? l) (k 'notfound)] [(eq? (car l) a) (cdr l)] [(atom? (car l)) (cons (car l) (aux (cdr l) k))] - ; what happens when (car l) exists but isn't an atom? - [else (let ([car2 (let/cc k2 ; now what will happen when k2 is called? - (aux (car l) k2))]) - (cond - ; when will the following condition be met? what happens then? - [(eq? car2 'notfound) (cons (car l) (aux (cdr l) k))] - [else (cons car2 (cdr l))]))]))] + [else + ; what happens when (car l) exists but isn't an atom? + (let ([car2 (let/cc k2 ; now what will happen when k2 is called? + (aux (car l) k2))]) + (cond + ; when will the following condition be met? what happens then? + [(eq? car2 'notfound) (cons (car l) (aux (cdr l) k))] + [else (cons car2 (cdr l))]))]))] [lst2 (let/cc k1 ; now what will happen when k1 is called? (aux lst k1))]) (cond @@ -344,7 +345,6 @@ Next, try to figure out what this function does: [(eq? lst2 'notfound) lst] [else lst2])))) - Here is [the answer](/hints/cps_hint_3), but try to figure it out for yourself. Here is the hardest example. Try to figure out what this function does: @@ -397,11 +397,13 @@ Here is [the answer](/hints/cps_hint_4), but again, first try to figure it out f Delimited control operators =========================== -`callcc` is what's known as an *undelimited control operator*. That is, the continuations `outk` that get bound to our `k`s behave as though they include all the code from the `call/cc ...` out to *and including* the end of the program. +Here again is the CPS for `callcc`: + + [callcc (\k. body)] = \outk. (\k. [body] outk) (\v localk. outk v) -Often times it's more useful to use a different pattern, where we instead capture only the code from the invocation of our control operator out to a certain boundary, not including the end of the program. These are called *delimited control operators*. A variety of the latter have been formulated. +`callcc` is what's known as an *undelimited control operator*. That is, the continuations `outk` that get bound into our `k`s include all the code from the `call/cc ...` out to *and including* the end of the program. Calling such a continuation will never return any value to the call site. (See the technique employed in the `delta` example above, with the `(begin (let/cc k2 ...) ...)`, for a work-around.) -The most well-behaved from where we're coming from is the pair `reset` and `shift`. `reset` sets the boundary, and `shift` binds the continuation from the position where it's invoked out to that boundary. +Often times it's more useful to use a different pattern, where we instead capture only the code from the invocation of our control operator out to a certain boundary, not including the end of the program. These are called *delimited control operators*. A variety of these have been formulated. The most well-behaved from where we're coming from is the pair `reset` and `shift`. `reset` sets the boundary, and `shift` binds the continuation from the position where it's invoked out to that boundary. It works like this: @@ -482,7 +484,7 @@ If instead at the end we did `... foo 1 + 1000`, we'd get the result `1110`. The above OCaml code won't work out of the box; you have to compile and install a special library that Oleg wrote. We discuss it on our [translation page](/translating_between_ocaml_scheme_and_haskell). If you can't get it working, then you can play around with `shift` and `reset` in Scheme instead. Or in the Continuation monad. Or using CPS transforms of your code, with the help of the lambda evaluator. -The relevant CPS transforms will be performed by these helper functions: +You can make the lambda evaluator perform the required CPS transforms with these helper functions: let reset = \body. \outk. outk (body (\i i)) in let shift = \k_body. \midk. (\k. (k_body k) (\i i)) (\a localk. localk (midk a)) in