实现使用Scala的延续收益率(收益率回报)
-
18-09-2019 - |
题
一个人怎么可能实现使用Scala的延续C#yield return
?我希望能够写斯卡拉Iterator
s在相同的风格。刺在noreferrer">这斯卡拉新闻帖子上相关问题回答表明这是可能的,但尽管我一直在玩了一段时间分隔延续,我似乎无法准确地总结我的周围如何做到这一点的头。
解决方案
在我们介绍的延续,我们需要建立一些基础设施。
下面是一个蹦床上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
s成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
的 C#参考页一个例子显示了一些更高级的用法。
该类型可以是有点棘手习惯,但它所有的作品。
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) }
其他提示
我设法找到一种方式来做到这一点,几个小时的玩耍后。我认为这是简单的绕到我的头比迄今为止我见过的所有其他解决方案,虽然我做了以后很欣赏丰富的和的 Miles的解决方案。
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)
不隶属于 StackOverflow