trait CPS {
val dispatcher: Dispatcher
def immediate[T](pProc: => T)(implicit pEscape: Escape): Call[T] = {
new ImmediateCall(() => pProc)(pEscape)
}
def deferred[T](pProc: => T)(implicit pEscape: Escape): Call[T] = {
new DeferredCall(() => pProc)(pEscape)
}
trait Call[T] {
val escape: Escape
val procBlock: () => T
def evaluate(): T = procBlock()
def continuation(pContBlock: (T) => Unit): Continuation[T]
}
class DeferredCall[T](val procBlock: () => T)(implicit val escape: Escape) extends Call[T] {
def continuation(pContBlock: (T) => Unit): Continuation[T] = {
new Continuation(pContBlock, this)
}
}
class ImmediateCall[T](val procBlock: () => T)(implicit val escape: Escape) extends Call[T] {
def continuation(pContBlock: (T) => Unit): Continuation[T] = {
val cont = new Continuation(pContBlock, this)
cont()
cont
}
}
class Continuation[T](val contBlock: (T) => Unit, val call: Call[T]) {
def apply() {
dispatcher.dispatch(call.procBlock, contBlock, call.escape)
}
}
trait Dispatcher {
def dispatch[T](pProcBlock: () => T, pContBlock: (T) => Unit, pEscape: Escape): Unit
}
trait Escape {
def apply(pThrowable: Throwable): Unit
}
}
object BlockingCPS extends CPS {
val dispatcher: Dispatcher = new Dispatcher {
def dispatch[T](pProcBlock: () => T, pContBlock: (T) => Unit, pEscape: Escape): Unit = {
try {
pContBlock(pProcBlock())
} catch {
case t => pEscape(t)
}
}
}
}
object NonBlockingCPS extends CPS {
import akka.actor.Actor
import akka.actor.Actor._
case class Run[T](val procBlock: () => T, val contBlock: (T) => Unit, val escape: Escape)
class CPSRunner extends Actor {
def receive = {
case Run(procBlock, contBlock, escape) =>
try {
contBlock(procBlock())
} catch {
case t => escape(t)
}
}
}
val dispatcher: Dispatcher = new Dispatcher {
def dispatch[T](pProcBlock: () => T, pContBlock: (T) => Unit, pEscape: Escape): Unit = {
try {
runnerRef ! Run(pProcBlock, pContBlock, pEscape)
} catch {
case t => pEscape(t)
}
}
}
private val runnerRef = actorOf[CPSRunner]
runnerRef.start()
}
object Examples {
import NonBlockingCPS._
implicit object EscapeHandler extends Escape {
def apply(pThrowable: Throwable): Unit = {
println("Escaping test block with error: " + pThrowable)
pThrowable.printStackTrace()
}
}
def main(args: Array[String]) {
runFactorial()
runStringToDecimal()
}
def runFactorial() {
factorial(0)
factorial(1)
factorial(2)
factorial(3)
factorial(4)
factorial(5)
factorial(6)
factorial(7)
factorial(8)
def printResult(pResult: (Int, Int)) {
println("%d! = %d".format(pResult._1, pResult._2))
}
def factorial(pNumber: Int) {
pNumber match {
case 0 => printResult((0, 1))
case n => factIter(1, pNumber)
}
def factIter(product: Int, n: Int) {
immediate {
(n * product, n)
} continuation { folding: (Int, Int) =>
if (folding._2 < 2) printResult((pNumber, folding._1))
else factIter(folding._1, folding._2 - 1)
}
}
}
}
def runStringToDecimal() {
val stringToDecimal = deferred {
"123"
} continuation { string =>
immediate {
BigDecimal(string)
} continuation { decimal =>
println("Decimal: " + decimal)
}
}
stringToDecimal()
stringToDecimal()
stringToDecimal()
}
}