High Wizardry in the Land of Scala

4,708 views

Published on

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

No Downloads
Views
Total views
4,708
On SlideShare
0
From Embeds
0
Number of Embeds
164
Actions
Shares
0
Downloads
85
Comments
0
Likes
16
Embeds 0
No embeds

No notes for slide



































































  • High Wizardry in the Land of Scala

    1. 1. High Wizardry in the Land of Scala Daniel Spiewak
    2. 2. Agenda • Higher-Kinds • Typeclasses • Type-Level Encodings • Continuations
    3. 3. Higher-Kinds • What is a “kind system”?
    4. 4. Higher-Kinds • What is a “kind system”? • What is a “type system”?
    5. 5. A type system is a tractable syntactic method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute. – Benjamin Pierce
    6. 6. val i: Int = 42 val j: Int = 21 val s: String = "foo" val f: Int => String = { _.toString } val xs: List[Int] = List(1, 1, 2, 3, 5, 8)
    7. 7. Values
    8. 8. Types Values
    9. 9. ??? Types Values
    10. 10. Kinds Types Values
    11. 11. Higher-Kinds • Type systems classify values • Kind systems classify types • Values are to types as types are to kinds
    12. 12. type Int :: * type String :: * type (Int => String) :: * type List[Int] :: *
    13. 13. type List :: ??? type Function1 :: ???
    14. 14. type List :: * => * type Function1 :: (* × *) => *
    15. 15. // id : Int => Int def id(x: Int) = x // Id :: * => * type Id[A] = A
    16. 16. // id : ((Int => Int), Int) => Int def id(f: Int => Int, x: Int) = f(x) // Id :: ((* => *) × *) => * type Id[A[_], B] = A[B]
    17. 17. val map: Map[Option[Any], List[Any]] = Map( Some("foo") -> List("foo", "bar", "baz"), Some(42) -> List(1, 1, 2, 3, 5, 8), Some(true) -> List(true, false, true, true)) // ugly cast! val xs: List[String] = map(Some("foo")).asInstanceOf[List[String]] // ditto! val ys: List[Int] = map(Some(42)).asInstanceOf[List[Int]]
    18. 18. val map: HOMap[Option, List] = HOMap[Option, List]( Some("foo") -> List("foo", "bar", "baz"), Some(42) -> List(1, 1, 2, 3, 5, 8), Some(true) -> List(true, false, true, true)) // blissful type safety! val xs: List[String] = map(Some("foo")) // ditto! val ys: List[Int] = map(Some(42))
    19. 19. // HOMap :: ((* => *) × (* => *)) => * class HOMap[K[_], V[_]](delegate: Map[K[Any], V[Any]]) { def apply[A](key: K[A]): V[A] = delegate(key.asInstanceOf[K[Any]]).asInstanceOf[V[A]] } object HOMap { def apply[K[_], V[_]](tuples: (K[Any], V[Any])*) = new HOMap[K, V](Map(tuples: _*)) } (credit: Jorge Ortiz)
    20. 20. Higher-Kinds • Kind systems classify types • Values are to types as types are to kinds • “Higher” kinds are the kinds of type constructors • Type functions • Use any time one type is logically a function of another
    21. 21. Typeclasses • Forget everything you know about classes • (it won’t help you anyway) • Instead of “class”, think “category” • If you’ve ever looked at Haskell…
    22. 22. sum(List(1, 2, 3, 4)) // => 10 sum(List(3.14, 2.72)) // => 5.86 sum(List("me", "you")) // shouldn't compile!
    23. 23. trait Num[A] { val zero: A def add(x: A, y: A): A } def sum[A](nums: List[A])(tc: Num[A]) = nums.foldLeft(tc.zero)(tc.add)
    24. 24. object IntNum extends Num[Int] { val zero = 0 def add(x: Int, y: Int) = x + y } object DoubleNum extends Num[Double] { val zero = 0d def add(x: Double, y: Double) = x + y }
    25. 25. // works! sum(List(1, 2, 3, 4))(IntNum) sum(List(3.14, 2.72))(DoubleNum)
    26. 26. Typeclasses • This is functional, but ugly • We have to explicitly provide the relevant instance of Num[A]
    27. 27. Typeclasses • This is functional, but ugly • We have to explicitly provide the relevant instance of Num[A]
    28. 28. def sum[A](nums: Seq[A])(tc: Num[A]) = nums.foldLeft(tc.zero)(tc.add)
    29. 29. def sum[A](nums: Seq[A])(implicit tc: Num[A]) = nums.foldLeft(tc.zero)(tc.add)
    30. 30. object IntNum extends Num[Int] { val zero = 0 def add(x: Int, y: Int) = x + y } object DoubleNum extends Num[Double] { val zero = 0d def add(x: Double, y: Double) = x + y }
    31. 31. implicit object IntNum extends Num[Int] { val zero = 0 def add(x: Int, y: Int) = x + y } implicit object DoubleNum extends Num[Double] { val zero = 0d def add(x: Double, y: Double) = x + y }
    32. 32. sum(List(1, 2, 3, 4))(IntNum) sum(List(3.14, 2.72))(DoubleNum)
    33. 33. sum(List(1, 2, 3, 4)) sum(List(3.14, 2.72))
    34. 34. Typeclasses • Typeclasses are categories of types • If you have a set of types with well-defined commonalities, think about typeclasses • Collections in 2.8 • Numeric in 2.8
    35. 35. Type-Level Encodings • Kinds make our types into superheroes • Typeclasses allow us to abstract over types • How can we abuse our new-found power?
    36. 36. Type-Level Encodings • Kinds make our types into superheroes • Typeclasses allow us to abstract over types • How can we abuse our new-found power? • Maybe…data structures at the type level?
    37. 37. Type-Level Encodings • HList is a linked-list implemented in types • …and values • Sort of like Tuple, but unbounded
    38. 38. import HList._ val xs = 42 :: "foo" :: 3.14 :: HNil xs.head // => 42: Int xs.tail.head // => "foo": String
    39. 39. val xs1 = 42 :: false :: HNil val xs2 = "Hello" :: "World" :: HNil val xs = xs1 ++ xs2 xs.head // => 42: Int xs.tail.tail.head // => "Hello": String
    40. 40. object HList { sealed trait HList { type Head type Tail <: HList type Append[L <: HList] <: HList def head: Head def tail: Tail def ++[L <: HList](xs: L): Append[L] } // ... }
    41. 41. val x: List[Int] = ... val y: List[Int] = ... x ++ y x 1 2 3 4 y 5 6 7 8 9
    42. 42. val x: List[Int] = ... val y: List[Int] = ... x ++ y x 2 3 4 y 5 6 7 8 9
    43. 43. val x: List[Int] = ... val y: List[Int] = ... x ++ y x 3 4 y 5 6 7 8 9
    44. 44. val x: List[Int] = ... val y: List[Int] = ... x ++ y x 4 y 5 6 7 8 9
    45. 45. val x: List[Int] = ... val y: List[Int] = ... x ++ y x’ y 5 6 7 8 9
    46. 46. val x: List[Int] = ... val y: List[Int] = ... x ++ y x’ 4 y 5 6 7 8 9
    47. 47. val x: List[Int] = ... val y: List[Int] = ... x ++ y x’ 3 4 y 5 6 7 8 9
    48. 48. val x: List[Int] = ... val y: List[Int] = ... x ++ y x’ 2 3 4 y 5 6 7 8 9
    49. 49. val x: List[Int] = ... val y: List[Int] = ... x ++ y x’ 1 2 3 4 y 5 6 7 8 9
    50. 50. object HList { // ... final class HNil extends HList { type Head = Nothing type Tail = Nothing type Append[L <: HList] = L def head = error("Head of an empty HList") def tail = error("Tail of an empty HList") def ::[A](a: A) = HCons(a, this) def ++[L <: HList](xs: L) = xs } val HNil = new HNil }
    51. 51. object HList { // ... case class HCons[A, B <: HList](head: A, tail: B) extends HList { type Head = A type Tail = B type Append[L <: HList] = HCons[Head, Tail#Append[L]] def ::[C](c: C) = HCons(c, this) def ++[L <: HList](xs: L) = head :: (tail ++ xs) } type ::[A, B <: HList] = HCons[A, B] }
    52. 52. Type-Level Encodings • What about an nth(Int) function?
    53. 53. Type-Level Encodings • What about an nth(Int) function? • Not today! • Church Numerals • λ-Calculus
    54. 54. Type-Level Encodings • What about an nth(Int) function? • Not today! • Church Numerals • λ-Calculus • We could do a lot more • Just not in a 45 minute talk
    55. 55. Continuations • Actually, delimited continuations • Very different from plain continuations! • Not like callcc • Not considered harmful • …though they can simulate goto!
    56. 56. case class JumpException(i: Int) extends RuntimeException val res = try { val i = 42 println("before") throw JumpException(i) // basically: `break` val j: Int = i / 2 println("after") println(j + 2) j // needed for type checker } catch { case JumpException(i) => i } println("outside")
    57. 57. val (res, func) = { val i = 42 println("before") (i, { j: Int => println("after") println(j + 2) }) } println("outside") func(res / 2) func(res / 6)
    58. 58. val (res, func) = reset { val i = 42 println("before") val j = shift { (k: Int => Unit) => (i, k) } println("after") println(j + 2) } println("outside") func(res / 2) func(res / 6)
    59. 59. val (res, func) = reset { val i = 42 println("before") val j = shift { (k: Int => Unit) => (i, k) } println("after") println(j + 2) } println("outside") func(res / 2) func(res / 6)
    60. 60. val (res, func) = reset { val i = 42 println("before") val j = shift { (k: Int => Unit) => (i, k) } println("after") println(j + 2) } println("outside") func(res / 2) func(res / 6)
    61. 61. val (res, func) = reset { val i = 42 println("before") val j = shift { (k: Int => Unit) => (i, k) } println("after") println(j + 2) } println("outside") func(res / 2) func(res / 6)
    62. 62. def gen() = { var x = 1 var y = 1 while (true) { shift { (k: Unit => Result) => Result(x, k) } y += x x = y - x } } val res = reset { gen() error("It never ends that way, too!"): Result } val fib: Stream[Int] = res.toStream (credit: PEP-255)
    63. 63. def gen() = { var x = 1 var y = 1 while (true) { shift { (k: Unit => Result) => Result(x, k) } y += x x = y - x } } val res = reset { gen() error("It never ends that way, too!"): Result } val fib: Stream[Int] = res.toStream (credit: PEP-255)
    64. 64. Continuations • This is cool and all, but what’s it good for?
    65. 65. Continuations • This is cool and all, but what’s it good for? • Not as much as you would think
    66. 66. reset { for (i <- 0 to 10) { shift { (k: Unit => Unit) => i } } }
    67. 67. reset { for (i <- 0 to 10) { shift { (k: Unit => Unit) => i } } }
    68. 68. Continuations • This is cool and all, but what’s it good for? • Not as much as you would think • Nonblocking I/O • Multi-page wizards • Framework support is needed
    69. 69. Conclusion • Higher-Kinds • Type Encodings • Classify types • Are really cool! • Typeclasses • Continuations • Categorize types • Powerful • ...but useless
    70. 70. Questions?

    ×