Imperative Web Workflows via Delimited Continuations

James Earl Douglas

July 9, 2012

def run() = {
  println("What is your name?")
  val name = readln()
  println("Hello, " + name + "!")
}

def run() = {
  println("What is your name?")
  val name = readln()
  println("Hello, " + name + "!")
}

val k = { name: String =>
  println("Hello, " + name + "!")
}

def run() = {
  println("What is your name?")
  k(readln())
}

def run() = reset {
  println("What is your name?")
  val name = shift { k: (String => Unit) =>
    val name = readln()
    k(name)
  }
  println("Hello, " + name + "!")
}

var c: String => Unit = _

def run() = reset {
  println("What is your name?")
  val name = shift { k: (String => Unit) =>
    c = k
  }
  println("Hello, " + name + "!")
}

scala> run()
What is your name?

scala> c("James")
Hello, James!

scala>

var c: String => Unit = _

def prompt() = shift {
  k: (String => Unit) => c = k
}

def run() = reset {
  println("What is your name?")
  val name = prompt()
  println("Hello, " + name + "!")
}

var c: String => Unit = _

def prompt() = shift {
  k: (String => Unit) => c = k
}

def run() = reset {
  println("What is your name?)
  val name = prompt()
  println("How old are you?)
  val age = prompt()
  println("Hello, " + name + "!")
  println("You are " + age + " years old.")
}

var c: String => Unit = _

def prompt() = shift {
  k: (String => Unit) => c = k
}

def run() = reset {
  println("What is your name?)
  val name = prompt()
  println("How old are you?)
  val age = prompt()
  println("Hello, " + name + "!")
  println("You are " + age + " years old.")
}

scala> run()
What is your name?

scala> c("James")
How old are you?

scala> c("29")
Hello, James!
You are 29 years old.

scala>

def run() = {
  println("What is your name?")
  val name = readln()
  println("How old are you?")
  val age = readln()
  println("Hello, " + name + "!")
  println("You are " + age + " years old.")
}

def run(): NodeSeq = reset {
  val name = prompt(<input name="Name" />)
  val age  = prompt(<input name="Age" />)
  <h1>Hello { name }!<h1>
  <p>You are { age } years old.</p>
}

def run(): NodeSeq = reset {
  val name = prompt(<input name="Name" />)
  val age  = prompt(<input name="Age" />)
  <h1>Hello { name }!<h1>
  <p>You are { age } years old.</p>
}

var step: (String => NodeSeq) = _ => run()

def prompt(html: NodeSeq): String @imp =
  shift { k: (String => NodeSeq) =>
    step = k
    html
  }

get("/") { step(params("input")) }

def getNameAndAge(
  params: Map[String, String] = Map.empty):
  (String, String) @imp = { ... }

def getBook(
  params: Map[String, String] = Map.empty):
  String @imp = { ... }

def run(): NodeSeq = reset {
  val (name, age) = getNameAndAge()
  val book = getBook()
  <h1>Hello { name }!<h1>
  <p>You are { age } years old.</p>
  <p>Your favorite book is { book }.</p>
}

def getBook(
  params: Map[String, String]):
  String @imp =
    params.get("Book") match {
      case None => prompt(...)
      case Some(book) => book
    }

Demo

def getItems(
  params: Map[String, String] = Map.empty,
  cart: List[Item] = Nil):
  List[Item] @imp = { ... }

^D