6. 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
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)
21. 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
22. 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…
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 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
}
32. 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
}
33. 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
}
36. 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
37. Type-Level Encodings
• Kinds make our types into superheroes
• Typeclasses allow us to abstract over types
• How can we abuse our new-found power?
38. 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?
39. Type-Level Encodings
• HList is a linked-list implemented in types
• …and values
• Sort of like Tuple, but unbounded
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]
}
56. 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
57. Continuations
• Actually, delimited continuations
• 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)
67. Continuations
• This is cool 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 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