Implicit Explicit Scala

3,502 views

Published on

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

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,502
On SlideShare
0
From Embeds
0
Number of Embeds
82
Actions
Shares
0
Downloads
12
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Implicit Explicit Scala

  1. 1. Implicit Explicit Scala 水島 宏太 (@kmizu)
  2. 2. 自己紹介
  3. 3. の前にお約束
  4. 4. JIT(Just In Tsukkomi)歓迎
  5. 5. @kmizu http://twitter.com/kmizu @ktmizushima (English) http://twitter.com/ktmizushima id:kmizushimahttp://d.hatena.ne.jp/kmizushima Scala辻斬り ヒーラー
  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との連携

×