Использование Scala продолжений для неблокирующих API

Я пытаюсь использовать продолжения Scala (2.9.0), чтобы построить API, казалось бы, блокирующий, но на самом деле он асинхронный. Предположим, что вы хотели бы написать что-то вроде:

if(ask("Continue?")) //Prompts Yes/No
  name = input("Enter your name")

Где ask возвращает логическое значение, если пользователь нажал да, и input запрашивает значение. Представьте, что это вызывается с веб-сервера, где ask и input не блокируют нити, они просто сохраняют продолжение на карте (или сеанс, не имеет значения) перед отображением страницы с подсказкой ( освобождая большинство ресурсов). И когда ответ возвращается, он просматривает продолжение на карте и возобновляет код.

Проблема до сих пор заключается в том, что я не могу найти подходящий способ определить ask и input для использования продолжений без передачи возвращаемого типа вызова в качестве параметра.

Самое близкое, что я получил, это что-то вроде:

#!/bin/sh
exec scala -P:continuations:enable -deprecation "$0" "[email protected]"
!#
import util.continuations._

//Api code
def display[T](prompt: String) = shift {
  cont: (Unit => T) => {
        println(prompt)
        cont()
    }
}

//Client code
def foo() : Int = reset {
  display[Int]("foo!") // <-- how do I get rid of the type annotation?
  5
}

def bar() : Unit = reset {
  display[Unit]("bar!")
}

println(foo())
bar()

Я действительно хотел бы избавиться от аннотации типа при вызовах display. Кто-нибудь знает способ достижения этого? Мне все равно, если определение API становится более уродливым, если код клиента упрощается. Спасибо!

Ответ 1

Я, наконец, понял:

#!/bin/sh
exec scala -P:continuations:enable -deprecation "$0" "[email protected]"
!#
import util.continuations._

class Display(val resume: (Unit => Any)) extends Throwable

//Api code
def display(prompt: String) = shift {
  cont: (Unit => Any) => {
        println(prompt)
        throw new Display(cont)
    }
}

//Client code
def foo() : Int = reset {
  display("foo!")
  5
}

def bar() : Unit = reset {
  display("bar!")
}

//Framework
try {
    foo()
} catch {
    case d: Display => println(d.resume())
}

try {
    bar()
} catch {
    case d: Display => d.resume() 
}

Трюк принимает методы, возвращающие Any (Homeresque: D'oh!) и возвращающие Nothing.

Если вы хотите реализовать что-то, возвращающее значение, например ask, вы можете сделать:

class Ask(val resume: (Boolean => Any)) extends Throwable

//Api code
def ask(prompt: String) = shift {
  cont: (Boolean => Any) => {
        println(prompt)
        throw new Ask(cont)
    }
}

В приведенном выше коде ask возвращает a Boolean.