High Wizardry in the Land
        of Scala
         Daniel Spiewak
Agenda

• Higher-Kinds
• Typeclasses
• Type-Level Encodings
• Continuations
Higher-Kinds


• What is a “kind system”?
Higher-Kinds


• What is a “kind system”?
• What is a “type system”?
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
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)
Values
Types


Values
???


Types


Values
Kinds


Types


Values
Higher-Kinds

• Type systems classify values
• Kind systems classify types
• Values are to types as types are to kinds
type Int :: *

type String :: *

type (Int => String) :: *

type List[Int] :: *
type List :: ???

type Function1 :: ???
type List :: * => *

type Function1 :: (* × *) => *
// id : Int => Int
def id(x: Int) = x

// Id :: * => *
type Id[A] = A
// id : ((Int => Int), Int) => Int
def id(f: Int => Int, x: Int) = f(x)

// Id :: ((* => *) × *) => *
type Id[A[_], B] = A[B]
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]]
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))
// 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)
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
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…
sum(List(1, 2, 3, 4))    // => 10
sum(List(3.14, 2.72))    // => 5.86
sum(List("me", "you"))   // shouldn't compile!
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)
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
}
// works!
sum(List(1, 2, 3, 4))(IntNum)
sum(List(3.14, 2.72))(DoubleNum)
Typeclasses


• This is functional, but ugly
• We have to explicitly provide the relevant
  instance of Num[A]
Typeclasses


• This is functional, but ugly
• We have to explicitly provide the relevant
  instance of Num[A]
def sum[A](nums: Seq[A])(tc: Num[A]) =
  nums.foldLeft(tc.zero)(tc.add)
def sum[A](nums: Seq[A])(implicit tc: Num[A]) =
  nums.foldLeft(tc.zero)(tc.add)
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
}
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
}
sum(List(1, 2, 3, 4))(IntNum)
sum(List(3.14, 2.72))(DoubleNum)
sum(List(1, 2, 3, 4))
sum(List(3.14, 2.72))
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
Type-Level Encodings

• Kinds make our types into superheroes
• Typeclasses allow us to abstract over types
• How can we abuse our new-found power?
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?
Type-Level Encodings

•   HList is a linked-list implemented in types

    • …and values
• Sort of like Tuple, but unbounded
import HList._

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

xs.head           // => 42: Int
xs.tail.head      // => "foo": String
val xs1 = 42 :: false :: HNil
val xs2 = "Hello" :: "World" :: HNil

val xs = xs1 ++ xs2

xs.head               // => 42: Int
xs.tail.tail.head     // => "Hello": String
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]
    }

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

        x ++ y



x   1    2       3       4



y   5    6       7       8       9
val x: List[Int] = ...
        val y: List[Int] = ...

        x ++ y



x        2       3       4



y   5    6       7       8       9
val x: List[Int] = ...
        val y: List[Int] = ...

        x ++ y



x                3       4



y   5    6       7       8       9
val x: List[Int] = ...
        val y: List[Int] = ...

        x ++ y



x                        4



y   5    6       7       8       9
val x: List[Int] = ...
         val y: List[Int] = ...

         x ++ y



x’


y    5    6       7       8       9
val x: List[Int] = ...
         val y: List[Int] = ...

         x ++ y



x’                        4



y    5    6       7       8       9
val x: List[Int] = ...
         val y: List[Int] = ...

         x ++ y



x’                3       4



y    5    6       7       8       9
val x: List[Int] = ...
         val y: List[Int] = ...

         x ++ y



x’        2       3       4



y    5    6       7       8       9
val x: List[Int] = ...
         val y: List[Int] = ...

         x ++ y



x’   1    2       3       4



y    5    6       7       8       9
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
}
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]
}
Type-Level Encodings
• What about an nth(Int) function?
Type-Level Encodings
• What about an nth(Int) function?
• Not today!
 • Church Numerals
 • λ-Calculus
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
Continuations

• Actually, delimited continuations
 • Very different from plain continuations!
 • Not like callcc
• Not considered harmful
 • …though they can simulate goto!
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")
val (res, func) = {
  val i = 42
  println("before")

    (i, { j: Int =>
       println("after")
       println(j + 2)
    })
}

println("outside")
func(res / 2)
func(res / 6)
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)
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)
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)
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)
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)
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)
Continuations


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


• This is cool and all, but what’s it good for?
• Not as much as you would think
reset {
  for (i <- 0 to 10) {
    shift { (k: Unit => Unit) => i }
  }
}
reset {
  for (i <- 0 to 10) {
    shift { (k: Unit => Unit) => i }
  }
}
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
Conclusion

• Higher-Kinds          • Type Encodings
 •   Classify types      •   Are really cool!

• Typeclasses           • Continuations
 •   Categorize types    •   Powerful

                         •   ...but useless
Questions?

High Wizardry in the Land of Scala

  • 1.
    High Wizardry inthe Land of Scala Daniel Spiewak
  • 3.
    Agenda • Higher-Kinds • Typeclasses •Type-Level Encodings • Continuations
  • 4.
    Higher-Kinds • What isa “kind system”?
  • 5.
    Higher-Kinds • What isa “kind system”? • What is a “type system”?
  • 6.
    A type systemis 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
  • 7.
    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)
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
    Higher-Kinds • Type systemsclassify values • Kind systems classify types • Values are to types as types are to kinds
  • 13.
    type Int ::* type String :: * type (Int => String) :: * type List[Int] :: *
  • 14.
    type List ::??? type Function1 :: ???
  • 15.
    type List ::* => * type Function1 :: (* × *) => *
  • 16.
    // id :Int => Int def id(x: Int) = x // Id :: * => * type Id[A] = A
  • 17.
    // id :((Int => Int), Int) => Int def id(f: Int => Int, x: Int) = f(x) // Id :: ((* => *) × *) => * type Id[A[_], B] = A[B]
  • 18.
    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]]
  • 19.
    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))
  • 20.
    // 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)
  • 21.
    Higher-Kinds • Kind systemsclassify 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
  • 22.
    Typeclasses • Forget everythingyou know about classes • (it won’t help you anyway) • Instead of “class”, think “category” • If you’ve ever looked at Haskell…
  • 24.
    sum(List(1, 2, 3,4)) // => 10 sum(List(3.14, 2.72)) // => 5.86 sum(List("me", "you")) // shouldn't compile!
  • 25.
    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)
  • 26.
    object IntNum extendsNum[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 }
  • 27.
    // works! sum(List(1, 2,3, 4))(IntNum) sum(List(3.14, 2.72))(DoubleNum)
  • 28.
    Typeclasses • This isfunctional, but ugly • We have to explicitly provide the relevant instance of Num[A]
  • 29.
    Typeclasses • This isfunctional, but ugly • We have to explicitly provide the relevant instance of Num[A]
  • 30.
    def sum[A](nums: Seq[A])(tc:Num[A]) = nums.foldLeft(tc.zero)(tc.add)
  • 31.
    def sum[A](nums: Seq[A])(implicittc: Num[A]) = nums.foldLeft(tc.zero)(tc.add)
  • 32.
    object IntNum extendsNum[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 }
  • 33.
    implicit object IntNumextends 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 }
  • 34.
    sum(List(1, 2, 3,4))(IntNum) sum(List(3.14, 2.72))(DoubleNum)
  • 35.
    sum(List(1, 2, 3,4)) sum(List(3.14, 2.72))
  • 36.
    Typeclasses • Typeclasses arecategories of types • If you have a set of types with well-defined commonalities, think about typeclasses • Collections in 2.8 • Numeric in 2.8
  • 37.
    Type-Level Encodings • Kindsmake our types into superheroes • Typeclasses allow us to abstract over types • How can we abuse our new-found power?
  • 38.
    Type-Level Encodings • Kindsmake 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?
  • 39.
    Type-Level Encodings • HList is a linked-list implemented in types • …and values • Sort of like Tuple, but unbounded
  • 40.
    import HList._ val xs= 42 :: "foo" :: 3.14 :: HNil xs.head // => 42: Int xs.tail.head // => "foo": String
  • 41.
    val xs1 =42 :: false :: HNil val xs2 = "Hello" :: "World" :: HNil val xs = xs1 ++ xs2 xs.head // => 42: Int xs.tail.tail.head // => "Hello": String
  • 42.
    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] } // ... }
  • 43.
    val x: List[Int]= ... val y: List[Int] = ... x ++ y x 1 2 3 4 y 5 6 7 8 9
  • 44.
    val x: List[Int]= ... val y: List[Int] = ... x ++ y x 2 3 4 y 5 6 7 8 9
  • 45.
    val x: List[Int]= ... val y: List[Int] = ... x ++ y x 3 4 y 5 6 7 8 9
  • 46.
    val x: List[Int]= ... val y: List[Int] = ... x ++ y x 4 y 5 6 7 8 9
  • 47.
    val x: List[Int]= ... val y: List[Int] = ... x ++ y x’ y 5 6 7 8 9
  • 48.
    val x: List[Int]= ... val y: List[Int] = ... x ++ y x’ 4 y 5 6 7 8 9
  • 49.
    val x: List[Int]= ... val y: List[Int] = ... x ++ y x’ 3 4 y 5 6 7 8 9
  • 50.
    val x: List[Int]= ... val y: List[Int] = ... x ++ y x’ 2 3 4 y 5 6 7 8 9
  • 51.
    val x: List[Int]= ... val y: List[Int] = ... x ++ y x’ 1 2 3 4 y 5 6 7 8 9
  • 52.
    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 }
  • 53.
    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] }
  • 54.
    Type-Level Encodings • Whatabout an nth(Int) function?
  • 55.
    Type-Level Encodings • Whatabout an nth(Int) function? • Not today! • Church Numerals • λ-Calculus
  • 56.
    Type-Level Encodings • Whatabout an nth(Int) function? • Not today! • Church Numerals • λ-Calculus • We could do a lot more • Just not in a 45 minute talk
  • 57.
    Continuations • Actually, delimitedcontinuations • Very different from plain continuations! • Not like callcc • Not considered harmful • …though they can simulate goto!
  • 58.
    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")
  • 59.
    val (res, func)= { val i = 42 println("before") (i, { j: Int => println("after") println(j + 2) }) } println("outside") func(res / 2) func(res / 6)
  • 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.
    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.
    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)
  • 63.
    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)
  • 64.
    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)
  • 65.
    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)
  • 66.
    Continuations • This iscool and all, but what’s it good for?
  • 67.
    Continuations • This iscool and all, but what’s it good for? • Not as much as you would think
  • 68.
    reset { for (i <- 0 to 10) { shift { (k: Unit => Unit) => i } } }
  • 69.
    reset { for (i <- 0 to 10) { shift { (k: Unit => Unit) => i } } }
  • 70.
    Continuations • This iscool 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
  • 71.
    Conclusion • Higher-Kinds • Type Encodings • Classify types • Are really cool! • Typeclasses • Continuations • Categorize types • Powerful • ...but useless
  • 72.