建立延續的功能

如果在分隔 reset 塊之外呼叫 shift,它可以用於建立自己在 reset 塊內建立延續的函式。值得注意的是,shift 的型別不僅僅是 (((A => B) => C) => A),它實際上是 (((A => B) => C) => (A @cpsParam[B, C]))。該註釋標記了需要 CPS 轉換的位置。在沒有 reset 的情況下呼叫 shift 的函式的返回型別會被該註釋感染

reset 區塊內,A @cpsParam[B, C] 的值似乎具有 A 的值,但實際上它只是假裝。完成計算所需的延續型別為 A => B,因此返回此型別的方法後面的程式碼必須返回 BC真實返回型別,在 CPS 轉換後,函式呼叫的型別為 C

現在,這個例子取自庫的 Scaladoc

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)
}

這裡,ask 會將延續儲存到地圖中,稍後其他一些程式碼可以檢索該會話並將查詢結果傳遞給使用者。通過這種方式,go 實際上可以使用非同步庫,而其程式碼看起來像普通的命令式程式碼。