Successfully reported this slideshow.
Upcoming SlideShare
×

# Implicit Explicit Scala

3,919 views

Published on

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

Published in: Technology
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Sex in your area is here: ❤❤❤ http://bit.ly/2u6xbL5 ❤❤❤

Are you sure you want to  Yes  No

Are you sure you want to  Yes  No

### Implicit Explicit Scala

1. 1. Implicit Explicit Scala 水島 宏太 (@kmizu)
2. 2. 自己紹介
3. 3. の前にお約束
4. 4. JIT(Just In Tsukkomi)歓迎
6. 6. Continuation Workshop 2011 (2011/09/24)限定継続の人(Tiark Rompf)が来てた あ、ありのまま(ry
7. 7. ちなみにこの自己紹介は(ry
8. 8. 今回説明すること
9. 9. その前にQuiz * 3
10. 10. ルール：-Xprint:typer禁止
11. 11. 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)
12. 12. A.1val 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]]
13. 13. Why ?
14. 14. Q.2 A1, A2, B1, B2 を埋めてくださいval l1 = List(1, 2, 3)val l2 = List(1.5, 2.5, 3.5)l1.suml2.suml1.sum[A1](?:A2)l2.sum[B2](?:B2)
15. 15. A.2val l1 = List(1, 2, 3)val l2 = List(1.5, 2.5, 3.5)l1.suml2.suml1.sum[Int](?:Numeric[Int])l2.sum[Double](?:Numeric[Double])
16. 16. Why ?
17. 17. Q.3 A1-A3, B1-B3 を埋めてくださいval l1 = List("A" -> 1, "B" -> 2)val l2 = List(1, 2, 3)l1.toMapl2.toMapl1.toMap[A1, A2](?:A3)l2.toMap[B1, B2](?:B3)
18. 18. A.3val l1 = List("A" -> 1, "B" -> 2)val l2 = List(1, 2, 3)l1.toMapl2.toMapl1.toMap[String, Int](?: (String, Int) <:< (String, Int))l2.toMap[B1, B2](?:B3)→ error: Cannot prove that Int <:< (T, U).
19. 19. Why ?
20. 20. 3つに共通するもの
21. 21. それは
22. 22. Implicit Parameter
23. 23. Implicit Parameter
24. 24. 最も誤解されてきた機能
25. 25. 実はとても強力な機能
26. 26. implicit parameter=省略可能引数
27. 27. とりあえず
28. 28. implicit parameter
29. 29. が今回のメイン
30. 30. A.1～A.3の意味がわかる ようになる(はず)
31. 31. 基本
32. 32. def hoge(implicit x: Int) = x + 3implicit val INT: Int = 3println(hoge) → println(hoge(INT)) → 6
33. 33. 間違いではないが
34. 34. 全然嬉しくない
35. 35. 基本
36. 36. 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))
37. 37. implicit宣言された型に適合する implicitな値を拾ってくれる
38. 38. implicit探索規則
39. 39. 基本：静的スコープで決まる
40. 40. メソッド呼び出し時に「直接参 照可能な」implicitな値が対象
41. 41. 「直接参照可能な」の意味1. 同一スコープにimplicitな値が定義されている2. importによってimplicitな値が導入されている
42. 42. 例外規則
43. 43. implicit parameterの型に「関連付けられ たクラス/トレイト」のコンパニオンオ ブジェクトも探索対象
44. 44. 「関連付けられたクラス/トレイト」
45. 45. trait G[A, B, C] の場合：G, A, B, C のコンパニオンオブジェクトを探索
46. 46. trait Addible[A] { def plus(x: A, y: A): A def zero: A}object Addible { //companion object 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)) // OK
47. 47. デフォルトで探索対象にして欲しいimplicitな値をコンパニオンオブジェクト に入れると便利
48. 48. 何が嬉しい？
49. 49. Doubleもsumしたくなった
50. 50. implicit object DoubleAddible extends Addible[Int] { def plus(x: Double, y: Double): Double = x + y def zero: Double = 0.0}println(sum(List(1.0, 2.0, 3.0)))→ println(sum(List(1.0, 2.0, 3.0))(DoubleAddible))
51. 51. 元のデータ型に変更を加えずに
52. 52. データ型の性質を新しく定義
53. 53. 特殊：implicit推論規則
54. 54. implicitな値から型パラメータを 「逆向きに」推論可能
55. 55. Scala 2.8で導入
56. 56. 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
57. 57. Aに応じて推論されるBが変わる
58. 58. 2.8コレクションには不可欠
59. 59. A.1 ～ A.3の定義をもう一度見てみる
60. 60. A.1val m = Map("A" -> 1, "B" -> 2)// def map [B, That] (f: ((A, B)) ⇒ B)(implicit bf: CanBuildFrom[Map[A, B], B, That]): Thatm.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]])
61. 61. 引数の型情報から順方向に推論 したのではThatはわからないimplicit推論規則による解決
62. 62. scala.collection.immutable.Map のコンパニオンオブジェクト
63. 63. package scala.collectionpackage immutableobject Map ... { .. //Coll = Map[_, _] implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), Map[A, B]] = new MapCanBuildFrom[A, B]}
64. 64. (1) 任意の型A, B について CanBuildFrom[Map[_, _], (A, B), Map[A, B]]型のimplicitな値を生成可能
65. 65. scala.collection.Iterableのコンパニオンオブジェクト
66. 66. package scala.collection...object Iterable ... { .. //Coll = Iterable[A] implicit def canBuildFrom[A]: CanBuildFrom[Coll, (A), Iterable[A]] = new GenericCanBuildFrom[A]}
67. 67. (2) 任意の型A, B について CanBuildFrom[Iterable[_, _], (A), Iterable[A]]型のimplicitな値を生成可能
68. 68. 適用優先度： (1) > (2)
69. 69. (1)が適合していなくても (2)が適合すればOK
70. 70. A.2val l1 = List(1, 2, 3)val l2 = List(1.5, 2.5, 3.5)l1.suml2.sum// def sum [B >: A] (implicit num: Numeric[B]): Bl1.sum[Int](?:Numeric[Int])l2.sum[Double](?:Numeric[Double])
71. 71. package scala.math...object Numeric { trait IntIsIntegral extends Integral[Int] { def plus(x: Int, y: Int): Int = x + y def minus(x: Int, y: Int): Int = x - y def times(x: Int, y: Int): Int = x * y def quot(x: Int, y: Int): Int = x / y def rem(x: Int, y: Int): Int = x % y def negate(x: Int): Int = -x def fromInt(x: Int): Int = x def toInt(x: Int): Int = x.toInt def toLong(x: Int): Long = x def toFloat(x: Int): Float = x def toDouble(x: Int): Double = x } .. // Integeral[T] <: Numeric[T] なので、 Numeric[Int]のimplicitな値も同時に定義 // していることになる implicit object IntIsIntegral extends IntIsIntegral with Ordering.IntOrdering}
72. 72. A.3val l1 = List("A" -> 1, "B" -> 2)val l2 = List(1, 2, 3)l1.toMapl2.toMap 名状し難い型l1.toMap[String, Int](?: (String, Int) <:< (String, Int))l2.toMap[B1, B2](?:B3)→ error: Cannot prove that Int <:< (T, U).
73. 73. 答えはPredefの中に
74. 74. 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]}
75. 75. ポイント
76. 76. sealed abstract class <:<[-From, +To]implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
77. 77. 任意の型AについてA <: A 型のimplicitな値を生成 可能(多相的なimplicit)
78. 78. 名状し難い <:< の左辺：contravariant (-) 右辺: covariant(+)
79. 79. def fun[A, B](a: A, b: B)(implicit ev: A <:< B)
80. 80. A = Int, B = Any つまり A <: B のとき(Int <:< Any) なimplicitな値が必要
81. 81. (Int <:< Int) <: (Int <:< Any) なので (<:< の右辺はcovariant)conforms[Int]: Int <: Int で適合する
82. 82. A = Any, B = Int つまり A <: B のとき(Any <:< Int) なimplicitな値が必要
83. 83. (Any <:< Any) <: (Any <: Int) かつ (Int <:< Int) <: (Any <: Int) (<:< の左辺はcontravariant) →コンパイルエラー
84. 84. implicit parameterを使ったライブラリ/フレームワーク
85. 85. Scala標準ライブラリ Scalaz sjson ScalaCheck spray Akka Squeryl ...
86. 86. たくさんある
87. 87. implicit parameterを活用してみてください
88. 88. 通称コップ本 第二版 好評発売中Scala 2.8対応+付録Scala 2.9記事(by @kmizu)
89. 89. 宣伝(2)
90. 90. こんなキーワードにピンと来たら(ry Cakeパターン, CONCEPTパターン, 限定継続 現場でのScala, Javaとの連携