72
High Wizardry in the Land of Scala Daniel Spiewak

High Wizardry in the Land of Scala

Embed Size (px)

Citation preview

Page 1: High Wizardry in the Land of Scala

High Wizardry in the Land of ScalaDaniel Spiewak

Page 2: High Wizardry in the Land of Scala
Page 3: High Wizardry in the Land of Scala

Agenda

• Higher-Kinds

• Typeclasses

• Type-Level Encodings

• Continuations

Page 4: High Wizardry in the Land of Scala

Higher-Kinds

• What is a “kind system”?

Page 5: High Wizardry in the Land of Scala

Higher-Kinds

• What is a “kind system”?

• What is a “type system”?

Page 6: High Wizardry in the Land of Scala

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

Page 7: High Wizardry in the Land of Scala

val i: Int = 42val j: Int = 21

val s: String = "foo"

val f: Int => String = { _.toString }

val xs: List[Int] = List(1, 1, 2, 3, 5, 8)

Page 8: High Wizardry in the Land of Scala

Values

Page 9: High Wizardry in the Land of Scala

Values

Types

Page 10: High Wizardry in the Land of Scala

Values

Types

???

Page 11: High Wizardry in the Land of Scala

Values

Types

Kinds

Page 12: High Wizardry in the Land of Scala

Higher-Kinds

• Type systems classify values

• Kind systems classify types

• Values are to types as types are to kinds

Page 13: High Wizardry in the Land of Scala

type Int :: *

type String :: *

type (Int => String) :: *

type List[Int] :: *

Page 14: High Wizardry in the Land of Scala

type List :: ???

type Function1 :: ???

Page 15: High Wizardry in the Land of Scala

type List :: * => *

type Function1 :: (* × *) => *

Page 16: High Wizardry in the Land of Scala

// id : Int => Intdef id(x: Int) = x

// Id :: * => *type Id[A] = A

Page 17: High Wizardry in the Land of Scala

// id : ((Int => Int), Int) => Intdef id(f: Int => Int, x: Int) = f(x)

// Id :: ((* => *) × *) => *type Id[A[_], B] = A[B]

Page 18: High Wizardry in the Land of Scala

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]]

Page 19: High Wizardry in the Land of Scala

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))

Page 20: High Wizardry in the Land of Scala

// 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)

Page 21: High Wizardry in the Land of Scala

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

Page 22: High Wizardry in the Land of Scala

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…

Page 23: High Wizardry in the Land of Scala
Page 24: High Wizardry in the Land of Scala

sum(List(1, 2, 3, 4)) // => 10sum(List(3.14, 2.72)) // => 5.86sum(List("me", "you")) // shouldn't compile!

Page 25: High Wizardry in the Land of Scala

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)

Page 26: High Wizardry in the Land of Scala

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}

Page 27: High Wizardry in the Land of Scala

// works!sum(List(1, 2, 3, 4))(IntNum)sum(List(3.14, 2.72))(DoubleNum)

Page 28: High Wizardry in the Land of Scala

Typeclasses

• This is functional, but ugly

• We have to explicitly provide the relevant instance of Num[A]

Page 29: High Wizardry in the Land of Scala

Typeclasses

• This is functional, but ugly

• We have to explicitly provide the relevant instance of Num[A]

Page 30: High Wizardry in the Land of Scala

def sum[A](nums: Seq[A])(tc: Num[A]) = nums.foldLeft(tc.zero)(tc.add)

Page 31: High Wizardry in the Land of Scala

def sum[A](nums: Seq[A])(implicit tc: Num[A]) = nums.foldLeft(tc.zero)(tc.add)

Page 32: High Wizardry in the Land of Scala

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}

Page 33: High Wizardry in the Land of Scala

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}

Page 34: High Wizardry in the Land of Scala

sum(List(1, 2, 3, 4))(IntNum)sum(List(3.14, 2.72))(DoubleNum)

Page 35: High Wizardry in the Land of Scala

sum(List(1, 2, 3, 4))sum(List(3.14, 2.72))

Page 36: High Wizardry in the Land of Scala

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

Page 37: High Wizardry in the Land of Scala

Type-Level Encodings

• Kinds make our types into superheroes

• Typeclasses allow us to abstract over types

• How can we abuse our new-found power?

Page 38: High Wizardry in the Land of Scala

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?

Page 39: High Wizardry in the Land of Scala

Type-Level Encodings

• HList is a linked-list implemented in types

• …and values

• Sort of like Tuple, but unbounded

Page 40: High Wizardry in the Land of Scala

import HList._

val xs = 42 :: "foo" :: 3.14 :: HNil

xs.head // => 42: Intxs.tail.head // => "foo": String

Page 41: High Wizardry in the Land of Scala

val xs1 = 42 :: false :: HNilval xs2 = "Hello" :: "World" :: HNil

val xs = xs1 ++ xs2

xs.head // => 42: Intxs.tail.tail.head // => "Hello": String

Page 42: High Wizardry in the Land of Scala

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] } // ...}

Page 43: High Wizardry in the Land of Scala

x

y

val x: List[Int] = ...val y: List[Int] = ...

x ++ y

1 2 3 4

5 6 7 8 9

Page 44: High Wizardry in the Land of Scala

x

y

val x: List[Int] = ...val y: List[Int] = ...

x ++ y

2 3 4

5 6 7 8 9

Page 45: High Wizardry in the Land of Scala

x

y

val x: List[Int] = ...val y: List[Int] = ...

x ++ y

3 4

5 6 7 8 9

Page 46: High Wizardry in the Land of Scala

x

y

val x: List[Int] = ...val y: List[Int] = ...

x ++ y

4

5 6 7 8 9

Page 47: High Wizardry in the Land of Scala

y

val x: List[Int] = ...val y: List[Int] = ...

x ++ y

5 6 7 8 9

x’

Page 48: High Wizardry in the Land of Scala

y

val x: List[Int] = ...val y: List[Int] = ...

x ++ y

5 6 7 8 9

4x’

Page 49: High Wizardry in the Land of Scala

y

val x: List[Int] = ...val y: List[Int] = ...

x ++ y

3

5 6 7 8 9

4x’

Page 50: High Wizardry in the Land of Scala

y

val x: List[Int] = ...val y: List[Int] = ...

x ++ y

2 3

5 6 7 8 9

4x’

Page 51: High Wizardry in the Land of Scala

y

val x: List[Int] = ...val y: List[Int] = ...

x ++ y

1 2 3

5 6 7 8 9

4x’

Page 52: High Wizardry in the Land of Scala

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}

Page 53: High Wizardry in the Land of Scala

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]}

Page 54: High Wizardry in the Land of Scala

Type-Level Encodings

• What about an nth(Int) function?

Page 55: High Wizardry in the Land of Scala

Type-Level Encodings

• What about an nth(Int) function?

• Not today!

• Church Numerals

• λ-Calculus

Page 56: High Wizardry in the Land of Scala

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

Page 57: High Wizardry in the Land of Scala

Continuations

• Actually, delimited continuations

• Very different from plain continuations!

• Not like callcc

• Not considered harmful

• …though they can simulate goto!

Page 58: High Wizardry in the Land of Scala

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")

Page 59: High Wizardry in the Land of Scala

val (res, func) = { val i = 42 println("before") (i, { j: Int => println("after") println(j + 2) })}

println("outside")func(res / 2)func(res / 6)

Page 60: High Wizardry in the Land of Scala

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)

Page 61: High Wizardry in the Land of Scala

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)

Page 62: High Wizardry in the Land of Scala

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)

Page 63: High Wizardry in the Land of Scala

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)

Page 64: High Wizardry in the Land of Scala

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)

Page 65: High Wizardry in the Land of Scala

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)

Page 66: High Wizardry in the Land of Scala

Continuations

• This is cool and all, but what’s it good for?

Page 67: High Wizardry in the Land of Scala

Continuations

• This is cool and all, but what’s it good for?

• Not as much as you would think

Page 68: High Wizardry in the Land of Scala

reset { for (i <- 0 to 10) { shift { (k: Unit => Unit) => i } }}

Page 69: High Wizardry in the Land of Scala

reset { for (i <- 0 to 10) { shift { (k: Unit => Unit) => i } }}

Page 70: High Wizardry in the Land of Scala

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

Page 71: High Wizardry in the Land of Scala

Conclusion

• Higher-Kinds

• Classify types

• Typeclasses

• Categorize types

• Type Encodings

• Are really cool!

• Continuations

• Powerful

• ...but useless

Page 72: High Wizardry in the Land of Scala

Questions?