90
Implicit Explicit Scala 水島 宏太 (@kmizu)

Implicit Explicit Scala

Embed Size (px)

DESCRIPTION

Scalaのimplicit parameter入門的な何かです。

Citation preview

Page 1: Implicit Explicit Scala

Implicit Explicit Scala

水島 宏太

(@kmizu)

Page 2: Implicit Explicit Scala

自己紹介

Page 3: Implicit Explicit Scala

の前にお約束

Page 4: Implicit Explicit Scala

JIT(Just In Tsukkomi)歓迎

Page 5: Implicit Explicit Scala

@kmizu http://twitter.com/kmizu

@ktmizushima (English) http://twitter.com/ktmizushima

id:kmizushima

http://d.hatena.ne.jp/kmizushima

Scala辻斬り ヒーラー

Page 6: Implicit Explicit Scala

Continuation Workshop 2011 (2011/09/24)

限定継続の人(Tiark Rompf)が来てた

あ、ありのまま(ry

Page 7: Implicit Explicit Scala

ちなみにこの自己紹介は(ry

Page 8: Implicit Explicit Scala

今回説明すること

Page 9: Implicit Explicit Scala

その前にQuiz * 3

Page 10: Implicit Explicit Scala

ルール:-Xprint:typer禁止

Page 11: Implicit Explicit Scala

Q.1 A1-A3, B1-B3 を埋めてください

val m = Map("A" -> 1, "B" -> 2)

m.map{case (x, y) => (y, x)}

m.map{case (x, y) => x}

m.map[A1, A2]({case (x, y) => (y, x) })(?:A3)

m.map[B1, B2]{case (x, y) => x })(?:B3)

Page 12: Implicit Explicit Scala

A.1

val m = Map("A" -> 1, "B" -> 2)

m.map{case (x, y) => (y, x)}

m.map{case (x, y) => x}

m.map[(Int, String), Map[Int, String]]{ case (x, y) => (y, x) }(?:CanBuildFrom[Map[String, Int], String,

Map[Int, String])

m.map[String, Iterable[String]]({ case (x, y) => x })

(?:CanBuildFrom[Map[String, Int], String, Iterable[String]]

Page 13: Implicit Explicit Scala

Why ?

Page 14: Implicit Explicit Scala

Q.2 A1, A2, B1, B2 を埋めてください

val l1 = List(1, 2, 3)

val l2 = List(1.5, 2.5, 3.5)

l1.sum

l2.sum

l1.sum[A1](?:A2)

l2.sum[B2](?:B2)

Page 15: Implicit Explicit Scala

A.2

val l1 = List(1, 2, 3)

val l2 = List(1.5, 2.5, 3.5)

l1.sum

l2.sum

l1.sum[Int](?:Numeric[Int])

l2.sum[Double](?:Numeric[Double])

Page 16: Implicit Explicit Scala

Why ?

Page 17: Implicit Explicit Scala

Q.3 A1-A3, B1-B3 を埋めてください

val l1 = List("A" -> 1, "B" -> 2)

val l2 = List(1, 2, 3)

l1.toMap

l2.toMap

l1.toMap[A1, A2](?:A3)

l2.toMap[B1, B2](?:B3)

Page 18: Implicit Explicit Scala

A.3

val l1 = List("A" -> 1, "B" -> 2)

val l2 = List(1, 2, 3)

l1.toMap

l2.toMap

l1.toMap[String, Int](?: (String, Int) <:< (String, Int))

l2.toMap[B1, B2](?:B3)

→ error: Cannot prove that Int <:< (T, U).

Page 19: Implicit Explicit Scala

Why ?

Page 20: Implicit Explicit Scala

3つに共通するもの

Page 21: Implicit Explicit Scala

それは

Page 22: Implicit Explicit Scala

Implicit Parameter

Page 23: Implicit Explicit Scala

Implicit Parameter

Page 24: Implicit Explicit Scala

最も誤解されてきた機能

Page 25: Implicit Explicit Scala

実はとても強力な機能

Page 26: Implicit Explicit Scala

implicit parameter=省略可能引数

Page 27: Implicit Explicit Scala

とりあえず

Page 28: Implicit Explicit Scala

implicit parameter

Page 29: Implicit Explicit Scala

が今回のメイン

Page 30: Implicit Explicit Scala

A.1~A.3の意味がわかる

ようになる(はず)

Page 31: Implicit Explicit Scala

基本

Page 32: Implicit Explicit Scala

def hoge(implicit x: Int) = x + 3

implicit val INT: Int = 3

println(hoge) → println(hoge(INT)) → 6

Page 33: Implicit Explicit Scala

間違いではないが

Page 34: Implicit Explicit Scala

全然嬉しくない

Page 35: Implicit Explicit Scala

基本

Page 36: Implicit Explicit Scala

trait Addible[A] {

def plus(x: A, y: A): A

def zero: A

}

implicit object IntAddible extends Addible[Int] {

def plus(x: Int, y: Int): Int = x + y

def zero: Int = 0

}

def sum[A](nums: List[A])(implicit addible: Addible[A]): A = {

nums.foldLeft(addible.zero)((x, y) => addible.plus(x, y))

}

println(sum(List(1, 2, 3, 4, 5)))

→ println(sum(List(1, 2, 3, 4, 5))(IntAddible))

Page 37: Implicit Explicit Scala

implicit宣言された型に適合する

implicitな値を拾ってくれる

Page 38: Implicit Explicit Scala

implicit探索規則

Page 39: Implicit Explicit Scala

基本:静的スコープで決まる

Page 40: Implicit Explicit Scala

メソッド呼び出し時に「直接参照可能な」implicitな値が対象

Page 41: Implicit Explicit Scala

「直接参照可能な」の意味

1. 同一スコープにimplicitな値が定義されている

2. importによってimplicitな値が導入されている

Page 42: Implicit Explicit Scala

例外規則

Page 43: Implicit Explicit Scala

implicit parameterの型に「関連付けられたクラス/トレイト」のコンパニオンオ

ブジェクトも探索対象

Page 44: Implicit Explicit Scala

「関連付けられたクラス/トレイト」

Page 45: Implicit Explicit Scala

trait G[A, B, C] の場合:

G, A, B, C のコンパニオンオブジェクトを探索

Page 46: Implicit Explicit Scala

trait Addible[A] {def plus(x: A, y: A): Adef zero: A

}object Addible { //companion objectimplicit object IntAddible extends Addible[Int] {def plus(x: Int, y: Int): Int = x + ydef zero: Int = 0

}}

def sum[A](nums: List[A])(implicit addible: Addible[A]): A = {nums.foldLeft(addible.zero)((x, y) => addible.plus(x, y))

}

println(sum(List(1, 2, 3, 4, 5)))→ println(sum(List(1, 2, 3, 4, 5))(IntAddible)) // OK

Page 47: Implicit Explicit Scala

デフォルトで探索対象にして欲しい

implicitな値をコンパニオンオブジェクト

に入れると便利

Page 48: Implicit Explicit Scala

何が嬉しい?

Page 49: Implicit Explicit Scala

Doubleもsumしたくなった

Page 50: Implicit Explicit Scala

implicit object DoubleAddible extends Addible[Int] {def plus(x: Double, y: Double): Double = x + ydef zero: Double = 0.0

}

println(sum(List(1.0, 2.0, 3.0)))→ println(sum(List(1.0, 2.0, 3.0))(DoubleAddible))

Page 51: Implicit Explicit Scala

元のデータ型に変更を加えずに

Page 52: Implicit Explicit Scala

データ型の性質を新しく定義

Page 53: Implicit Explicit Scala

特殊:implicit推論規則

Page 54: Implicit Explicit Scala

implicitな値から型パラメータを

「逆向きに」推論可能

Page 55: Implicit Explicit Scala

Scala 2.8で導入

Page 56: Implicit Explicit Scala

implicit val tupleA: (Int, String) = (1, "A")implicit val tupleB: (Double, String) = (1.5, "B")

def useImplicitTuple2[A, B](value: A)(implicit tuple: (A, B)): B = {tuple._2

}println(useImplicitTuple2(100)) // Aprintln(useImplicitTuple2(1.5)) // B

Page 57: Implicit Explicit Scala

Aに応じて推論されるBが変わる

Page 58: Implicit Explicit Scala

2.8コレクションには不可欠

Page 59: Implicit Explicit Scala

A.1 ~ A.3の定義を

もう一度見てみる

Page 60: Implicit Explicit Scala

A.1val m = Map("A" -> 1, "B" -> 2)

// def map [B, That] (f: ((A, B)) ⇒ B)

(implicit bf: CanBuildFrom[Map[A, B], B, That]): That

m.map{case (x, y) => (y, x)}

m.map{case (x, y) => x}

m.map[(Int, String), Map[Int, String]]{ case (x, y) => (y, x) }(?:CanBuildFrom[Map[String, Int],

String, Map[Int, String])

m.map[String, Iterable[String]]({ case (x, y) => x })

(?:CanBuildFrom[Map[Int, String], String, Iterable[String]])

Page 61: Implicit Explicit Scala

引数の型情報から順方向に推論したのではThatはわからない

implicit推論規則による解決

Page 62: Implicit Explicit Scala

scala.collection.immutable.Map

のコンパニオンオブジェクト

Page 63: Implicit Explicit Scala

package scala.collection

package immutable

object Map ... {

..

//Coll = Map[_, _]

implicit def canBuildFrom[A, B]:

CanBuildFrom[Coll, (A, B), Map[A, B]] =

new MapCanBuildFrom[A, B]

}

Page 64: Implicit Explicit Scala

(1) 任意の型A, B についてCanBuildFrom[Map[_, _], (A, B), Map[A, B]]

型のimplicitな値を生成可能

Page 65: Implicit Explicit Scala

scala.collection.Iterable

のコンパニオンオブジェクト

Page 66: Implicit Explicit Scala

package scala.collection

...

object Iterable ... {

..

//Coll = Iterable[A]

implicit def canBuildFrom[A]:

CanBuildFrom[Coll, (A), Iterable[A]] =

new GenericCanBuildFrom[A]

}

Page 67: Implicit Explicit Scala

(2) 任意の型A, B についてCanBuildFrom[Iterable[_, _], (A), Iterable[A]]

型のimplicitな値を生成可能

Page 68: Implicit Explicit Scala

適用優先度: (1) > (2)

Page 69: Implicit Explicit Scala

(1)が適合していなくても

(2)が適合すればOK

Page 70: Implicit Explicit Scala

A.2

val l1 = List(1, 2, 3)

val l2 = List(1.5, 2.5, 3.5)

l1.sum

l2.sum

// def sum [B >: A] (implicit num: Numeric[B]): B

l1.sum[Int](?:Numeric[Int])

l2.sum[Double](?:Numeric[Double])

Page 71: Implicit Explicit Scala

package scala.math...object Numeric { trait IntIsIntegral extends Integral[Int] {def plus(x: Int, y: Int): Int = x + ydef minus(x: Int, y: Int): Int = x - ydef times(x: Int, y: Int): Int = x * ydef quot(x: Int, y: Int): Int = x / ydef rem(x: Int, y: Int): Int = x % ydef negate(x: Int): Int = -xdef fromInt(x: Int): Int = xdef toInt(x: Int): Int = x.toIntdef toLong(x: Int): Long = xdef toFloat(x: Int): Float = xdef toDouble(x: Int): Double = x

}..// Integeral[T] <: Numeric[T] なので、 Numeric[Int]のimplicitな値も同時に定義// していることになるimplicit object IntIsIntegral extends IntIsIntegral withOrdering.IntOrdering

}

Page 72: Implicit Explicit Scala

A.3

val l1 = List("A" -> 1, "B" -> 2)

val l2 = List(1, 2, 3)

l1.toMap

l2.toMap

l1.toMap[String, Int](?: (String, Int) <:< (String, Int))

l2.toMap[B1, B2](?:B3)

→ error: Cannot prove that Int <:< (T, U).

名状し難い型名状し難い型名状し難い型

Page 73: Implicit Explicit Scala

答えはPredefの中に

Page 74: Implicit Explicit Scala

package scala.math

...

object Predef ... {

@implicitNotFound(msg = "Cannot prove that ${From} <:< ${To}.")

sealed abstract class <:<[-From, +To] extends (From => To) with Serializable

private[this] final val singleton_<:< = new <:<[Any,Any] {

def apply(x: Any): Any = x }

// not in the <:< companion object because it is also

// intended to subsume identity (which is no longer implicit)

implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]

}

名状し難い型の定義

Page 75: Implicit Explicit Scala

ポイント

Page 76: Implicit Explicit Scala

sealed abstract class <:<[-From, +To]

implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]

Page 77: Implicit Explicit Scala

任意の型Aについて

A <: A 型のimplicitな値を生成

可能(多相的なimplicit)

Page 78: Implicit Explicit Scala

名状し難い <:< の

左辺:contravariant (-)

右辺: covariant(+)

Page 79: Implicit Explicit Scala

def fun[A, B](a: A, b: B)(implicit ev: A <:< B)

Page 80: Implicit Explicit Scala

A = Int, B = Any

つまり A <: B のとき

(Int <:< Any) なimplicitな値が必要

Page 81: Implicit Explicit Scala

(Int <:< Int) <: (Int <:< Any) なので

(<:< の右辺はcovariant)

conforms[Int]: Int <: Int で適合する

Page 82: Implicit Explicit Scala

A = Any, B = Int

つまり A <: B のとき

(Any <:< Int) なimplicitな値が必要

Page 83: Implicit Explicit Scala

(Any <:< Any) <: (Any <: Int) かつ

(Int <:< Int) <: (Any <: Int)

(<:< の左辺はcontravariant)

→コンパイルエラー

Page 84: Implicit Explicit Scala

implicit parameterを使った

ライブラリ/フレームワーク

Page 85: Implicit Explicit Scala

Scala標準ライブラリScalazsjson

ScalaChecksprayAkka

Squeryl...

Page 86: Implicit Explicit Scala

たくさんある

Page 87: Implicit Explicit Scala

implicit parameterを

活用してみてください

Page 88: Implicit Explicit Scala

通称コップ本 第二版 好評発売中

Scala 2.8対応+付録Scala 2.9記事(by @kmizu)

Page 89: Implicit Explicit Scala

宣伝(2)

Page 90: Implicit Explicit Scala

こんなキーワードにピンと来たら(ry

Cakeパターン, CONCEPTパターン, 限定継続

現場でのScala, Javaとの連携