Created
July 24, 2011 13:07
-
-
Save kmizu/1102602 to your computer and use it in GitHub Desktop.
An example of generator library. This is used for explaining shift/reset and this code cannot be compiled Because @susp is eliminated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.continuations.ControlContext._ | |
import scala.continuations._ | |
import scala.collection._ | |
/* | |
* C#形式のイテレータを表現したトレイト | |
*/ | |
trait Generator[+A] extends Traversable[A] { | |
def moveNext(): Boolean | |
def current: A | |
//ここではこれだけ実装しておけば、後の高階関数は勝手に定義してくれる | |
def foreach[U](f: A => U): Unit = { | |
while(moveNext()) { | |
f(current) | |
} | |
} | |
} | |
object Generator { | |
def make[A](body: (A => Unit) => Unit): Generator[A] = new Generator[A] { | |
val yields: A => Unit = {v => // vはyieldの呼び出し時に渡される値 | |
//kの中には、「yieldsが呼ばれた後の実行状態」が保存されていて、kを呼び出すと、ユーザ側コードの実行が再開される | |
shift{k: (Unit => Any) => | |
//kとvの組を返す | |
(k, v):Any //(X) shiftの呼び出しが終わると、再内のresetの呼出し後(1)まで大域的に脱出してしまう。 | |
} | |
} | |
//(A)thunkは実行状態を保存しておくための変数。初期状態では、↓のようになっているが、それ以降は継続が代入される。 | |
var thunk: Unit => Any = {x: Unit => | |
//実行状態をキャプチャする準備 | |
reset { | |
//引数にyields↑を渡してbodyを呼び出す | |
body(yields) //この行の実行中に、yieldが呼ばれたら、一気に(1)まで脱出する((X)に対応)。 | |
None //yieldsが呼び出せるブロックの実行が全て終わったらここに到達する。このとき、resetの返り値はNoneになる(=終了) | |
} | |
//(1) (k, v)の組がresetの戻り値になる。 | |
} | |
var value: A = _ | |
def moveNext(): Boolean = { | |
val result = thunk() //thunkの呼び出し。初回は、上記の(A)に代入された関数が呼び出される。 | |
//結果をパターンマッチ。(k, v)の組かNoneのどちらかであるはず。 | |
result match { | |
//継続と値のペアが返って来た、ということはまだ「次」があるということ | |
case (k, v) => | |
//型がAnyになってしまっているので、キャストして代入 | |
thunk = k.asInstanceOf[(Unit => Any)] //thunkにキャプチャした実行状態が保存される | |
value = v.asInstanceOf[A] //yieldで渡された値をvalueに代入 | |
true //次があるのでtrue | |
case None => | |
false //ブロックの最後まで到達したのでfalse | |
} | |
} | |
def current: A = value | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Generator._ | |
object User { | |
def upto[A](from: Int, to: Int)(f: Int => A ): Unit = { | |
if(from <= to) { f(from); upto(from + 1, to)(f) } | |
} | |
def main(args: Array[String]) { | |
// 1から10までの数を列挙するジェネレータ | |
val g1 = make[Int] {yields => | |
upto(1, 10) {i => | |
yields(i) これを呼び出すと、Generator.scala中の`yields`が呼ばれる | |
} | |
} | |
while(g1.moveNext()) { | |
println(g1.current) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment