yield return
Scalaの継続を使用してC#をどのように実装できますか?Iterator
同じスタイルでScalaを書けるようになりたいです。このScalaニュース投稿のコメントに刺し傷がありますが、機能しません(Scala 2.8.0ベータ版を使用して試してみました)。関連する質問の回答は、これが可能であることを示唆していますが、私はしばらくの間、区切られた継続で遊んでいますが、これを行う方法に頭を悩ませているようには見えません。
2 に答える
継続を導入する前に、いくつかのインフラストラクチャを構築する必要があります。以下は物の上で動作するトランポリン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
andreset
演算子を使用して計算を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) }
ずっといい!
次に、より高度な使用法を示す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) }
さらに数時間遊んだ後、なんとかこれを行う方法を発見しました。これは、これまでに見た他のすべてのソリューションよりも頭を包み込むのが簡単だと思いましたが、その後、リッチとマイルズのソリューションに非常に感謝しました.
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)