Top Banner
High Wizardry in the Land of Scala Daniel Spiewak
72

High Wizardry in the Land of Scala

May 12, 2015

Download

Technology

djspiewak
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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?