Учитывая канонический пример из research paper для разграниченных продолжений Scala, слегка измененный, поэтому задана функция, вводимая в shift
имя f
и, следовательно, уже не является анонимным.
def f(k: Int => Int): Int = k(k(k(7)))
reset(
shift(f) + 1 // replace from here down with `f(k)` and move to `k`
) * 2
Скала плагин преобразует этот пример таким образом, что вычисление (в пределах входного аргумента reset
), начиная с каждого shift
с вызовом reset
является заменен с функцией (например f
) ввода в shift
.
Замененное вычисление смещено (т. Е. Перемещено) в функцию k
. Функция f
вводит функцию k
, где k
содержит замененного вычисление, k
входов x: Int
и вычисление в k
заменяют shift(f)
с x
.
f(k) * 2
def k(x: Int): Int = x + 1
который имеет тот же эффект, как:
k(k(k(7))) * 2
def k(x: Int): Int = x + 1
Обратите внимание на тип Int
входного параметра x
(т.е. тип подписи k
) был дан тип подписи входного параметра f
,
Другой borrowed пример с концептуально эквивалентной абстракции, т.е. read
функция вход shift
:
def read(callback: Byte => Unit): Unit = myCallback = callback
reset {
val byte = "byte"
val byte1 = shift(read) // replace from here with `read(callback)` and move to `callback`
println(byte + "1 = " + byte1)
val byte2 = shift(read) // replace from here with `read(callback)` and move to `callback`
println(byte + "2 = " + byte2)
}
Я считаю, что это будет переведено на логический эквивалент:
val byte = "byte"
read(callback)
def callback(x: Byte): Unit {
val byte1 = x
println(byte + "1 = " + byte1)
read(callback2)
def callback2(x: Byte): Unit {
val byte2 = x
println(byte + "2 = " + byte1)
}
}
Я надеюсь, это объясняет когерентную общую абстракцию, которая была несколько запутана предшествующим представлением этих двух примеров. Например, канонический первый пример был представлен в research paper как анонимная функция, вместо моего имени f
, поэтому некоторые читатели не сразу поняли, что он был абстракционно подобен второму примеру read
в borrowed.
Таким образом, разграниченные продолжения создают иллюзию инверсии управления из «вы называете меня из-за пределов reset
» на «Я звоню вам внутри reset
».
Примечания возвращаемого типа f
есть, но k
нет, требуется, чтобы быть таким же, как тип возвращаемого reset
, т.е. f
имеет право на свободу, чтобы объявить любой тип возвращаемых данных для k
, пока f
возвращает тот же типа, reset
. То же для read
и capture
(см. Также ENV
ниже).
Ограниченные продолжения не неявно инвертируют управление состоянием, например. read
и callback
не являются чистыми функциями. Таким образом, вызывающий объект не может создавать ссылочно прозрачные выражения и, следовательно, не имеет declarative (a.k.a. transparent) control over intended imperative semantics.
Мы можем явно получить чистые функции с разграниченными продолжениями.
def aread(env: ENV): Tuple2[Byte,ENV] {
def read(callback: Tuple2[Byte,ENV] => ENV): ENV = env.myCallback(callback)
shift(read)
}
def pure(val env: ENV): ENV {
reset {
val (byte1, env) = aread(env)
val env = env.println("byte1 = " + byte1)
val (byte2, env) = aread(env)
val env = env.println("byte2 = " + byte2)
}
}
Я считаю, что это будет переведено на логический эквивалент:
def read(callback: Tuple2[Byte,ENV] => ENV, env: ENV): ENV =
env.myCallback(callback)
def pure(val env: ENV): ENV {
read(callback,env)
def callback(x: Tuple2[Byte,ENV]): ENV {
val (byte1, env) = x
val env = env.println("byte1 = " + byte1)
read(callback2,env)
def callback2(x: Tuple2[Byte,ENV]): ENV {
val (byte2, env) = x
val env = env.println("byte2 = " + byte2)
}
}
}
Это становится шумным, из-за явной среды.
Заметьте, что у Scala нет глобального типа вывода Haskell, и, насколько мне известно, не может поддерживать неявный подъем до состояния монады unit
(как одна из возможных стратегий скрытия явной среды), потому что глобальный Haskell (Hindley -Milner), зависит от not supporting diamond multiple virtual inheritance.
http://www.scala-lang.org/api/current/index.html#scala.util.continuations.package – Vadzim