Skip to content

Instantly share code, notes, and snippets.

@lyricallogical
Created February 1, 2012 05:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lyricallogical/1715274 to your computer and use it in GitHub Desktop.
Save lyricallogical/1715274 to your computer and use it in GitHub Desktop.
rpscala67
!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