Scala Language Continuations Library Creating Functions That Take Continuations


Example

If shift is called outside of a delimiting reset block, it can be used to create functions that themselves create continuations inside a reset block. It is important to note that shift's type is not just (((A => B) => C) => A), it is actually (((A => B) => C) => (A @cpsParam[B, C])). That annotation marks where CPS transformations are needed. Functions that call shift without reset have their return type "infected" with that annotation.

Inside a reset block, a value of A @cpsParam[B, C] seems to have a value of A, though really it's just pretending. The continuation that is needed to complete the computation has type A => B, so the code following a method that returns this type must return B. C is the "real" return type, and after CPS transformation the function call has the type C.

Now, the example, taken from the Scaladoc of the library

val sessions = new HashMap[UUID, Int=>Unit]
def ask(prompt: String): Int @suspendable = // alias for @cpsParam[Unit, Unit]. @cps[Unit] is also an alias. (@cps[A] = @cpsParam[A,A])
  shift {
    k: (Int => Unit) => {
      println(prompt)
      val id = uuidGen
      sessions += id -> k
    }
  }

def go(): Unit = reset {
  println("Welcome!")
  val first = ask("Please give me a number") // Uses CPS just like shift
  val second = ask("Please enter another number")
  printf("The sum of your numbers is: %d\n", first + second)
}

Here, ask will store the continuation into a map, and later some other code can retrieve that "session" and pass in the result of the query to the user. In this way, go can actually be using an asynchronous library while its code looks like normal imperative code.