Как можно было бы реализовать C# yield return
использование продолжений Scala? Я хотел бы смочь записать Scala Iterator
s в том же стиле. Удар находится в комментариях к этому сообщению новостей Scala, но это не работает (пытался использовать Scala 2.8.0 бет). Ответы в связанном вопросе предполагают, что это возможно, но хотя я играл с разграниченными продолжениями некоторое время, я, может казаться, точно не переношу голову, как сделать это.
Прежде чем мы введем продолжения, нам нужно создать некоторую инфраструктуру.
Ниже приведен батут , который работает с объектами Iteration
.
Итерация - это a вычисление, которое может либо дать
новое значение, либо оно может быть 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
, вызывая итератор
полученного объекта потока.
При использовании Stream
наша оценка ленивая; мы не оцениваем нашу следующую итерацию, пока она не понадобится.
Батут можно использовать для создания итератора напрямую.
val itr1 = trampoline {
Yield(1, () => Yield(2, () => Yield(3, () => Done)))
}
for (i <- itr1) { println(i) }
Это довольно ужасно писать, поэтому давайте использовать продолжения с разделителями для автоматического создания наших объектов Iteration
.
Мы используем операторы shift
и reset
, чтобы разбить вычисление на итераций
с,
затем использовать батут
], чтобы превратить итерацию
в итератор
.
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) }
Намного лучше!
Вот пример со справочной страницы C # для 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) }
Я использовал ICE от ZeroC ( www.zeroc.com ), и это было фантастически. Супер прост в использовании, и это не только кроссплатформенный, но и имеет поддержку многих языков (python, java и т.д.) и даже встроенной версии библиотеки.
-121--2212718-Можно попробовать использовать Sqlite . Это очень быстро и обеспечит полную реализацию базы данных с SQL-запросами к файлу.
Если вы думаете попробовать двоичные форматы, я предлагаю вам попробовать это в первую очередь.
И может использоваться с ORM, и может быть сжат и зашифрован.
-121--3879679-Мне удалось найти способ сделать это, после нескольких часов игры вокруг. Я думал, что это проще обернуть голову вокруг, чем все другие решения, которые я видел до сих пор, хотя после этого я очень ценил решения Рича и Майлза .
def loopWhile(cond: =>Boolean)(body: =>(Unit @suspendable)): Unit @suspendable = {
if (cond) {
body
loopWhile(cond)(body)
}
}
class Gen {
var prodCont: Unit => Unit = { x: Unit => prod }
var nextVal = 0
def yld(i: Int) = shift { k: (Unit => Unit) => nextVal = i; prodCont = k }
def next = { prodCont(); nextVal }
def prod = {
reset {
// following is generator logic; can be refactored out generically
var i = 0
i += 1
yld(i)
i += 1
yld(i)
// scala continuations plugin can't handle while loops, so need own construct
loopWhile (true) {
i += 1
yld(i)
}
}
}
}
val it = new Gen
println(it.next)
println(it.next)
println(it.next)