相互再帰を最適化するものです。
私はプログラミングClojureを読んではじめて知りました。
相互再帰を最適化すると言っても、既存のものを最適化することは出来ません。
最適化のためには関数をトランポリンを使ったものにしなくてはなりません。
さて、そのトランポリンですが、実はScalazには用意されているのです!
多分6.0.4から入った・・・と思う。
私がStack Overflowで質問したからですね!フフン!
まぁ、たぶん質問しなくても入ってたと思いますが・・・・
なぜTrampolineが入ったのか
以下推測
それは、IOモナドの最適化のためだと思われます。
以前のIOモナドは、>>=で連結していくと評価時にIOの呼び出しが深くなってしまい、StackOverflowErrorを起こしていました。
そこで、トランポリンを導入することで最適化がされました。
命名規則をみると、Scalaz7から輸入されたようです。
なので、IOが問題になっていなかったら、Scalaz6では入っていなかったかも・・・?
使い方
プログラミングClojureの例を参考に偶数、奇数を調べる関数を書いてみる。
まずはトランポリンを使わずに
This file contains 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
lazy val odd: Int => Boolean = { | |
case 0 => false | |
case n => even(n - 1) | |
} | |
lazy val even: Int => Boolean = { | |
case 0 => true | |
case n => odd(n - 1) | |
} |
どれくらいでスタックがあふれるか調べる。
This file contains 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
assert(odd(1)) | |
assert(odd(11)) | |
assert(odd(111)) | |
assert(odd(1111)) | |
assert(odd(11111)) | |
// assert(odd(111111)) StackOverflow |
6桁で落ちるとは・・・・
トランポリン版
This file contains 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
lazy val odd: Int => Free.Trampoline[Boolean] = { | |
case 0 => Free.return_(false) | |
case n => Free.suspend(even(n - 1)) | |
} | |
lazy val even: Int => Free.Trampoline[Boolean] = { | |
case 0 => Free.return_(true) | |
case n => Free.suspend(odd(n-1)) | |
} |
実行するにはrunメソッドを呼びます。
This file contains 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
assert(odd(11111).run) | |
assert(odd(111111).run) | |
assert(odd(1111111).run) | |
assert(odd(11111111).run) | |
assert(odd(111111111).run) |
これは全く落ちない。
※追記
遅かった・・・・
結論
プログラミングClojureにあるとおり、なるべく最適なアルゴリズム、自己再帰で書きましょう。
IOモナドのような特殊なケースはあまりないと思います。
さて、このTrampoline、じつはtype aliasです。
type Trampoline [+A] = Free[Function0, A]
と定義されており、Freeがもっと一般化されたなにかであることがわかります。
Freeについてはいつか調べるor誰か調べてくれる・・・はず・・・・・
0 件のコメント:
コメントを投稿