Created
February 1, 2012 05:21
-
-
Save lyricallogical/1715274 to your computer and use it in GitHub Desktop.
rpscala67
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
!SLIDE | |
# virtualized pattern matcher の紹介 | |
!SLIDE | |
注意:大きな仕様変更があったので、このスライドの内容は古くなってしまいました | |
!SLIDE | |
## [Scala 2.10.0 Milestone 1 is released!](http://www.scala-lang.org/node/12250) | |
Included in this release are: | |
* Preliminary Reflection API | |
* faster inliner | |
* scaladoc improvements (Thanks docspree folks!) | |
* virtualized pattern matcher | |
* many more! | |
!SLIDE | |
## virtualized pattern matcher とは? | |
* pattern match の新しい実装 | |
* for-comprehension のように、メソッド呼び出しに変換する | |
* ML では virtualizing pattern matcher といわれてる(どっちだ) | |
* 以下 VPM | |
!SLIDE | |
## 何はともあれ実例 | |
これが | |
```scala | |
Option(0) match { | |
case Some(_) => 1 | |
case None => 2 | |
} | |
``` | |
!SLIDE | |
## 何はともあれ実例 結果 | |
こうなる | |
```scala | |
import MatchingStrategy.OptionMatchingStrategy._ | |
runOrElse(Option(0)) { x1 => | |
guard(x1.isInstanceOf[Some[Int]], x1.asInstanceOf[Some[Int]]).flatMap { x2 => | |
if (x2 != null) | |
one(1) | |
else | |
zero | |
} orElse { | |
guard(None == x1, x1).flatMap { x2 => | |
one(2) | |
} | |
} | |
} | |
``` | |
!SLIDE | |
## ね、簡単でしょ? | |
!SLIDE | |
## うそです | |
ひとつずつ見ていきましょう | |
!SLIDE | |
## scala.MatchingStrategy とは | |
```scala | |
abstract class MatchingStrategy[M[+x]] | |
``` | |
* match 式を変換する際に利用されるクラス | |
* for-comprehension は対象のオブジェクト自身のメソッドを呼び出す | |
* VPM は implicitly[MatchingStrategy[M]] のメソッドを呼び出す | |
!SLIDE | |
## 利用されるメソッド | |
以下の四つ | |
* runOrElse | |
* zero | |
* one | |
* guard | |
!SLIDE | |
## runOrElse メソッド | |
```scala | |
def runOrElse[T, U](in: T)(matcher: (T) ⇒ M[U]) : U | |
``` | |
in を matcher に適用し、結果を取り出す | |
!SLIDE | |
## zero | |
```scala | |
def zero: M[Nothing] | |
``` | |
「ゼロ」を表す値を返す | |
!SLIDE | |
## one | |
```scala | |
def one[T](x: T): M[T] | |
``` | |
M で包んだ値を返す | |
!SLIDE | |
## guard | |
```scala | |
def guard[T](cond: Boolean, then: ⇒ T): M[T] | |
``` | |
cond が true なら then を、そうでなければ zero を返す | |
!SLIDE | |
## case の変換 | |
```scala | |
case Some(_) => 1 | |
``` | |
!SLIDE | |
### Some かどうか判定する | |
```scala | |
x => x.isInstanceOf[Some[Int]] | |
``` | |
!SLIDE | |
### Some なら Option から Some にする | |
```scala | |
x => guard(x.isInstanceOf[Some[Int]], x.asInstanceOf[Some[Int]]) | |
``` | |
!SLIDE | |
### 更に結果を返すよう変換する | |
```scala | |
x => guard(x.isInstanceOf[Some[Int]], x.asInstanceOf[Some[Int]]).flatMap { _ => | |
one(1) | |
} | |
``` | |
実際には最初に見たように null チェックが入りますが本質的でないので省略 | |
!SLIDE | |
## case の変換 その 2 | |
```scala | |
x => gurad(None == x, x).flatMap { _ => one(2) } | |
``` | |
過程は同じなので省略 | |
!SLIDE | |
### case をつなぐ | |
```scala | |
x => | |
guard(x.isInstanceOf[Some[Int]], x.asInstanceOf[Some[Int]]).flatMap { _ => | |
one(1) | |
}.orElse { | |
gurad(None == x, x).flatMap { _ => one(2) } | |
} | |
``` | |
orElse でつなぐだけ | |
!SLIDE | |
## ね、簡単でしょ? | |
!SLIDE | |
## PartialFunction はどうなるの? | |
* MatchingStrategy には isSuccess というメソッドがある | |
* が、現在の実装では使われていない…! | |
* まあうまいことしてくれるんでしょう | |
!SLIDE | |
## VPM の使い方 | |
* undocumented です…! | |
* ML やソースを見れば -Yvirtpatmat オプションでよいと分かる | |
!SLIDE | |
## MatchingStrategy を差し替えてみよう | |
```scala | |
implicit object OptionMatchingStrategy extends MatchingStrategy[Option] { | |
type M[+x] = Option[x] | |
def guard[T](cond: Boolean, then: => T): M[T] = if(cond) Some(then) else None | |
def zero: M[Nothing] = None | |
def one[T](x: T): M[T] = { println("one!"); Some(x) } | |
def altFlatMap[T, U](f: T => M[U])(a: M[U], b: M[T]): M[U] = a orElse b.flatMap(f) | |
def runOrElse[T, U](x: T)(f: T => M[U]): U = f(x) getOrElse (throw new MatchError(x)) | |
def isSuccess[T, U](x: T)(f: T => M[U]): Boolean = !f(x).isEmpty | |
} | |
``` | |
one に println 突っ込んだだけ | |
!SLIDE | |
## Let's try! | |
!SLIDE | |
## 何もでない | |
!SLIDE | |
## おかしいぞ…! | |
* M が Option の場合は、MatchingStrategy を利用しない最適化されたツリーを出力するような実装になっている | |
* エッ…エッ? | |
* unapply メソッドが現状 Boolean, Option, Some の何れかしか返せないため、M は常に Option | |
* 今のところ MatchingStrategy 出番なし | |
!SLIDE | |
## どうすればいいの… | |
* 試したいなら[パッチ](https://gist.github.com/1710868)をあてて最適化を無効にしましょう | |
!SLIDE | |
## Let's try! | |
!SLIDE | |
## エッ | |
> error: type arguments [Option[Int]] do not conform to method orElse's type parameter bounds [B >: Int] | |
!SLIDE | |
## ナンデ!?型エラーナンデ!? | |
* 多分バグ | |
* なんだけど、最初の実装からこうなってる、よく分からない | |
* 最初から動いてなかった説…! | |
!SLIDE | |
## どうすればいいの… その 2 | |
* どうしても動かしたいなら[パッチ](https://gist.github.com/1715208)をあてましょう | |
* 正しい修正なのかどうかは知りません | |
!SLIDE | |
## 終わっていいですか | |
* もう疲れました | |
!SLIDE | |
## まとめ | |
* いつから | |
* VPM は for-comprehension のように match 式をメソッド呼び出しに変換する | |
* と錯覚していた? | |
* まだまだ開発中で色々と問題点、今後に期待 | |
!SLIDE | |
## 残された疑問点 | |
* orElse(plus) も MatchingStrategy に入れたほうがいいのでは? | |
* MatchingStrategy 型クラスのインスタンスの解決基準って何? | |
* unapply が Option しか許さない現状 MatchingStrategy[Option] 以外にありえないけどどうしたいの? | |
* 型エラーナンデ?? | |
!SLIDE | |
## おしまい |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment