package continuations
Delimited continuations are a feature for modifying the usual control flow
of a program. To use continuations, provide the option -P:continuations:enable
to the Scala compiler or REPL to activate the compiler plugin.
Below is an example of using continuations to suspend execution while awaiting user input. Similar facilities are used in so-called continuation-based web frameworks.
def go = reset { println("Welcome!") val first = ask("Please give me a number") val second = ask("Please enter another number") printf("The sum of your numbers is: %d\n", first + second) }
The reset is provided by this package and delimits the extent of the
transformation. The ask is a function that will be defined below. Its
effect is to issue a prompt and then suspend execution awaiting user input.
Once the user provides an input value, execution of the suspended block
resumes.
val sessions = new HashMap[UUID, Int=>Unit] def ask(prompt: String): Int @cps[Unit] = shift { k: (Int => Unit) => { val id = uuidGen printf("%s\nrespond with: submit(0x%x, ...)\n", prompt, id) sessions += id -> k } }
The type of ask includes a @cps annotation which drives the transformation.
The type signature Int @cps[Unit] means that ask should be used in a
context requiring an Int, but actually it will suspend and return Unit.
The computation leading up to the first ask is executed normally. The
remainder of the reset block is wrapped into a closure that is passed as
the parameter k to the shift function, which can then decide whether
and how to execute the continuation. In this example, the continuation is
stored in a sessions map for later execution. This continuation includes a
second call to ask, which is treated likewise once the execution resumes.
CPS Annotation
The aforementioned @cps[A] annotation is an alias for the more general
@cpsParam[B,C] where B=C. The type A @cpsParam[B,C] describes a term
which yields a value of type A within an evaluation context producing a
value of type B. After the CPS transformation, this return type is
modified to C.
The @cpsParam annotations are introduced by shift blocks, and propagate
via the return types to the dynamically enclosing context. The propagation
stops upon reaching a reset block.
- Alphabetic
- By Inheritance
- continuations
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Type Members
-
final
class
ControlContext
[+A, -B, +C] extends Serializable
This class represent a portion of computation that has a 'hole' in it.
This class represent a portion of computation that has a 'hole' in it. The class has the ability to compute state up until a certain point where the state has the
Atype. If this context is given a function of typeA => Bto move the state to theBtype, then the entire computation can be completed resulting in a value of typeC.An Example:
val cc = new ControlContext[String, String, String]( fun = { (f: String=>String, err: Exception => String) => val updatedState = try f("State") catch { case e: Exception => err(e) } updatedState + "-Complete!" }, x = null.asIntanceOf[String] } cc.foreach(_ + "-Continued") // Results in "State-Continued-Complete!"
This class is used to transform calls to
shiftin thecontinuationspackage. Direct use and instantiation is possible, but usually reserved for advanced cases.A context may either be trivial or non-trivial. A trivial context just has a state of type
A. When completing the computation, it's only necessary to use the function of typeA => Bdirectly against the trivial value. A non-trivial value stores a computation around the state transformation of typeA => Band cannot be short-circuited.- A
The type of the state currently held in the context.
- B
The type of the transformed state needed to complete this computation.
- C
The return type of the entire computation stored in this context.
- Note
funandxare allowed to benull.- See also
scala.util.continutations.shiftR
-
type
cps[A] = cpsParam[A, A]
An annotation that denotes a type is part of a continuation context.
An annotation that denotes a type is part of a continuation context.
@cps[A]is shorthand forcpsParam[A,A]. -
class
cpsParam
[-B, +C] extends Annotation with StaticAnnotation with TypeConstraint
This annotation is used to mark a parameter as part of a continuation context.
This annotation is used to mark a parameter as part of a continuation context.
The type
A @cpsParam[B,C]is desugared toControlContext[A,B,C]at compile time.- B
The type of computation state after computation has executed, and before control is returned to the shift.
- C
The eventual return type of this delimited compuation.
- See also
scala.util.continuations.ControlContext
-
type
suspendable = cpsParam[Unit, Unit]
An annotation that denotes a type is part of a side effecting continuation context.
An annotation that denotes a type is part of a side effecting continuation context.
@suspendableis shorthand notation for@cpsParam[Unit,Unit]or@cps[Unit].
Value Members
-
def
reify[A, B, C](ctx: ⇒ A @scala.util.continuations.cpsParam[B,C]): ControlContext[A, B, C]
This method converts from the sugared
A @cpsParam[B,C]type to the desugaredControlContext[A,B,C]type.This method converts from the sugared
A @cpsParam[B,C]type to the desugaredControlContext[A,B,C]type. The underlying data is not changed. - def reifyR[A, B, C](ctx: ⇒ ControlContext[A, B, C]): ControlContext[A, B, C]
-
def
reset[A, C](ctx: ⇒ A @scala.util.continuations.cpsParam[A,C]): C
Creates a context for continuations captured within the argument closure of this
resetcall and returns the result of the entire transformed computation.Creates a context for continuations captured within the argument closure of this
resetcall and returns the result of the entire transformed computation. Within an expression of the formreset { block }, the closure expression (block) will be modified such that at each call toshiftthe remainder of the expression is transformed into a function to be passed into the shift.- returns
The result of a block of code that uses
shiftto capture continuations.
- def reset0[A](ctx: ⇒ A @scala.util.continuations.cpsParam[A,A]): A
- def run[A](ctx: ⇒ Any @scala.util.continuations.cpsParam[Unit,A]): A
-
def
shift[A, B, C](fun: ((A) ⇒ B) ⇒ C): A @scala.util.continuations.cpsParam[B,C]
The
shiftfunction captures the remaining computation in aresetblock and passes it to a closure provided by the user.The
shiftfunction captures the remaining computation in aresetblock and passes it to a closure provided by the user.For example:
reset { shift { (k: Int => Int) => k(5) } + 1 }In this example,
shiftis used in the expressionshift ... + 1. The compiler will alter this expression so that the call toshiftbecomes a parameter to a function, creating something like:{ (k: Int => Int) => k(5) } apply { _ + 1 }The result of this expression is 6.
There can be more than one
shiftcall in aresetblock. Each call toshiftcan alter the return type of expression within the reset block, but will not change the return type of the entirereset { block }expression.- fun
A function where
- The parameter is the remainder of computation within the current
resetblock. This is passed as a functionA => B. - The return is the return value of the
ControlContextwhich is generated from this inversion.
- The parameter is the remainder of computation within the current
- Note
Must be invoked in the context of a call to
resetThis context may not be far up the stack, but a call to reset is needed to eventually remove the@cpsannotations from types.
-
def
shiftR[A, B, C](fun: ((A) ⇒ B) ⇒ C): ControlContext[A, B, C]
Captures a computation into a
ControlContext.Captures a computation into a
ControlContext.- fun
The function which accepts the inverted computation and returns a final result.
- See also
shift
- def shiftUnit[A, B, C >: B](x: A): A @scala.util.continuations.cpsParam[B,C]
- def shiftUnit0[A, B](x: A): A @scala.util.continuations.cpsParam[B,B]
- def shiftUnitR[A, B](x: A): ControlContext[A, B, B]