Использование продолжений Scala для неблокирующих API - PullRequest
11 голосов
/ 28 июля 2011

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

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

Где ask возвращает логическое значение, если пользователь нажал yes, а 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 более утомительным, если клиентский код становится проще.Спасибо!

1 Ответ

6 голосов
/ 28 июля 2011

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

#!/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 (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 возвращает Boolean.

...