Ответ 1
Прежде чем вводить продолжение, нам нужно построить некоторую инфраструктуру.
Ниже приведена trampoline, которая работает с объектами Iteration
.
Итерация - это вычисление, которое может либо Yield
иметь новое значение, либо оно может быть Done
.
sealed trait Iteration[+R]
case class Yield[+R](result: R, next: () => Iteration[R]) extends Iteration[R]
case object Done extends Iteration[Nothing]
def trampoline[R](body: => Iteration[R]): Iterator[R] = {
def loop(thunk: () => Iteration[R]): Stream[R] = {
thunk.apply match {
case Yield(result, next) => Stream.cons(result, loop(next))
case Done => Stream.empty
}
}
loop(() => body).iterator
}
Батут использует внутренний цикл, который превращает последовательность объектов Iteration
в Stream
.
Затем мы получаем Iterator
, вызывая Iterator
в результирующем объекте потока.
Используя Stream
, наша оценка ленива; мы не оцениваем нашу следующую итерацию, пока она не понадобится.
Батут можно использовать для непосредственного создания итератора.
val itr1 = trampoline {
Yield(1, () => Yield(2, () => Yield(3, () => Done)))
}
for (i <- itr1) { println(i) }
Это довольно ужасно для записи, поэтому давайте использовать разграниченные продолжения для автоматического создания объектов Iteration
.
Мы используем операторы shift
и reset
, чтобы разбить вычисление на Iteration
s,
затем используйте trampoline
, чтобы превратить Iteration
в Iterator
.
import scala.continuations._
import scala.continuations.ControlContext.{shift,reset}
def iterator[R](body: => Unit @cps[Iteration[R],Iteration[R]]): Iterator[R] =
trampoline {
reset[Iteration[R],Iteration[R]] { body ; Done }
}
def yld[R](result: R): Unit @cps[Iteration[R],Iteration[R]] =
shift((k: Unit => Iteration[R]) => Yield(result, () => k(())))
Теперь мы можем переписать наш пример.
val itr2 = iterator[Int] {
yld(1)
yld(2)
yld(3)
}
for (i <- itr2) { println(i) }
Гораздо лучше!
Теперь вот пример страницы С# для Yield
, которая показывает более продвинутое использование.
Типы могут быть немного сложными, чтобы привыкнуть, но все это работает.
def power(number: Int, exponent: Int): Iterator[Int] = iterator[Int] {
def loop(result: Int, counter: Int): Unit @cps[Iteration[Int],Iteration[Int]] = {
if (counter < exponent) {
yld(result)
loop(result * number, counter + 1)
}
}
loop(number, 0)
}
for (i <- power(2, 8)) { println(i) }