Created
November 20, 2012 15:53
-
-
Save lyricallogical/4118752 to your computer and use it in GitHub Desktop.
rpscala92
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 | |
implicit parameter 入門 | |
---------------- | |
!SLIDE | |
implicit parameter って? | |
---------------- | |
* 「Type Classes がどうのこうの」 | |
* 「Context Bounds がどうのこうの」 | |
* 「Functor がどうのこうの」 | |
* 「Monad がどうのこうの」 | |
* 「CanBuildFrom がどうのこうの」 | |
!SLIDE | |
わけがわかりません | |
---------------- | |
これはそんな人のためのスライドです かんたんだよ | |
!SLIDE | |
ぐたいれい | |
---------------- | |
* 文字列とか Json とかロギングするメソッドを定義する | |
* ロギングのために Logger を要求する | |
```scala | |
trait Logger { def log(msg: String): Unit } | |
def logString(str: String, logger: Logger) = ... | |
def logJson(jsValue: JsValue, logger: Logger) = ... | |
``` | |
!SLIDE | |
気を利かせた(つもり) | |
---------------- | |
* 「どうせ皆デフォルトの Logger 使うんでしょ」 | |
```scala | |
object Logger { val defaultLogger: Logger = ... } | |
def logString(str: String, logger: Logger = Logger.defaultLogger) = ... | |
def logJson(jsValue: JsValue, logger: Logger = Logger.defaultLogger) = ... | |
``` | |
!SLIDE | |
ところがどっこい | |
---------------- | |
* 「誰がデフォルトの Logger なんて使うか」 | |
* 思いは通じなかった… | |
```scala | |
logJson(json, new FooLogger) | |
logString((json \ "name").as[String], new FooLogger) | |
logJson(json \ "mother", new FooLogger) | |
``` | |
!SLIDE | |
reconsidering default parameter | |
---------------- | |
* コンテキストによって「デフォルト」は変わりうる | |
* しかし、デフォルト引数の値は後から変更できない | |
* ダメダメのダメダメダメです | |
!SLIDE | |
def, def, def and def! | |
---------------- | |
* メソッドを定義しまくってもいいけど… | |
* ダサい & だるい | |
```scala | |
def logStringWithFooLogger(str: String) = logString(str, new FooLogger) | |
def logJsonWithFooLogger(jsValue: JsValue) = logJson(jsValue, new FooLogger) | |
``` | |
!SLIDE | |
implicit parameter にご登場願いましょう | |
---------------- | |
* じゃーん(眠い)(ちょうど日付が変わる寸前です) | |
```scala | |
def logString(str: String)(implicit logger: Logger = Logger.defaultLogger) = ... | |
def logJson(jsValue: JsValue)(implicit logger: Logger = Logger.defaultLogger) = ... | |
``` | |
!SLIDE | |
何が変わった? | |
---------------- | |
* 外部からデフォルト値を変更することができるようになりました! | |
* implicit modifier がついてる値をコンパイラが探して | |
* 自動的に implicit parameter に渡してくれるよ | |
* 毎回渡さなくても良くなった! | |
```scala | |
{ | |
implicit val defaultLogger = new FooLogger | |
logJson(json) | |
logString((json \ "name").as[String]) | |
logJson(json \ "mother")(defaultLogger /* explicit に渡すこともできるよ */) | |
} | |
``` | |
!SLIDE | |
おしまい | |
---------------- | |
めでたしめでたし | |
!SLIDE | |
ではない | |
---------------- | |
まだもうちょっとある がんばれ(これ書いてるボクが) | |
!SLIDE | |
fluentd とか流行ってますよね | |
---------------- | |
* 突然の構造化 Logger | |
* さてどうしたものか | |
```scala | |
trait JsonLogger { def log(msg: JsValue): Unit } | |
``` | |
!SLIDE | |
generic! | |
---------------- | |
* ロギング対象が汎用的な trait を用意してあげよう | |
```scala | |
trait GenericLogger[T] { def log(t: T): Unit } | |
object Logger { val defaultLogger: GenericLogger[String] = ... } | |
object JsonLogger { val defaultLogger: GenericLogger[JsValue] = ... } | |
``` | |
!SLIDE | |
再定義 | |
---------------- | |
```scala | |
def logString(str: String)(implicit logger: GenericLogger[String] = Logger.defaultLogger) = ... | |
def logJson(jsValue: JsValue)(implicit logger: GenericLogger[JsValue] = JsonLogger.defaultLogger) = ... | |
``` | |
!SLIDE | |
generic, generic, generic and generic! | |
---------------- | |
* もうついでにロギングを行うメソッド自体も generic にしてしまえ! | |
* でも、デフォルト引数はどうしよう…? | |
```scala | |
def log[T](t: T)(implicit logger: GenericLogger[T] /* ここに書ける適切なデフォルト値がない */) = ... | |
``` | |
!SLIDE | |
companion object | |
---------------- | |
* ある class もしくは trait と名前がおんなじオブジェクト | |
* ここで implicit modifier つけて定義しておくと、コンパイラが見つけてくれる | |
* 型毎にデフォルト引数を用意しているようなものですね | |
```scala | |
trait GenericLogger[T] { def log(t: T): Unit } | |
object GenericLogger { | |
implicit val defaultStringLogger: GenericLogger[String] = ... | |
implicit val defaultJsonLogger: GenericLogger[JsValue] = ... | |
} | |
``` | |
!SLIDE | |
結果 | |
---------------- | |
* なんか綺麗さっぱりした | |
```scala | |
log(json) | |
log((json \ "name").as[String]) | |
log(json \ "mother") | |
``` | |
!SLIDE | |
贅沢な名前だね | |
---------------- | |
* 今日からお前の名前は Loggable だよ | |
```scala | |
trait Loggable[T] { def log(t: T): Unit } | |
object Loggable { | |
implicit val defaultStringLoggable: Loggable[String] = ... | |
implicit val defaultJsonLoggable: Loggable[JsValue] = ... | |
} | |
``` | |
!SLIDE | |
Loggable ってなんだ | |
---------------- | |
* 型 T がロギング可能であることをあらわす trait | |
* こういう「ある型に対する操作を提供する仕組み」を Type Classes と | |
* 呼ぶような 呼ばないような | |
```scala | |
trait Loggable[T] { def log(t: T): Unit } | |
``` | |
!SLIDE | |
ある型に対する操作の提供 | |
---------------- | |
* 継承/mixin も似たようなものじゃないの? | |
* あとからでも操作を提供できる | |
* 継承は型の定義時にしかできないよ | |
* implicit conversion も似たようなこと出来る | |
* けど今回は implicit parameter が主題だから話さないよ | |
!SLIDE | |
なんかしよう before | |
---------------- | |
* ログだけとっててもしかたない | |
* なんか処理するぞ ロギングもするぞ | |
* process では Loggable 使わないけど log が必要としている… | |
* ので implicit paramter 書く必要があるけどだるい | |
* それに渡すだけで使いもしない変数があるのはダサい | |
```scala | |
def process[T](t: T)(implicit ev: Loggable[T] /* ダサい */) = { | |
... | |
log(t) | |
... | |
} | |
``` | |
!SLIDE | |
なんかしよう after | |
---------------- | |
* Context Bounds! | |
* 型パラメタ T がロギング可能であることを要求している | |
* 単なる syntax sugar なので展開後は before みたいになります | |
```scala | |
def process[T : Loggable /* スマート! */](t: T) = { | |
... | |
log(t) | |
... | |
} | |
``` | |
!SLIDE | |
まとめ | |
---------------- | |
* implicit parameter = デフォルト値を外から変更できる default parameter | |
* というのはいいすぎだけれど、まあ大体そんなものです | |
* それに型変数が付いたときに Type Classes とかいってかっこつけるのです | |
* 書くのだるいときは Context Bounds という型制約が使えます | |
* 手前味噌ですが「型に対する制約」という視点からの説明も | |
* [http://www.slideshare.net/lyrical_logical/scala-14863557](http://www.slideshare.net/lyrical_logical/scala-14863557) | |
!SLIDE | |
do you have some questions? | |
---------------- | |
!SLIDE | |
おわり | |
---------------- | |
ねむかった |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment