Использование продолжений 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" "$@"
!#
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 становится более уродливым, пока клиентский код становится проще. Спасибо!


person juancn    schedule 27.07.2011    source источник
comment
Опубликуйте свой ответ как ответ.   -  person Daniel C. Sobral    schedule 28.07.2011


Ответы (1)


Я наконец-то понял:

#!/bin/sh
exec scala -P:continuations:enable -deprecation "$0" "$@"
!#
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 (по-гомерски: 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 возвращает Boolean.

person juancn    schedule 28.07.2011