November 11, 2016
940

# Spoiled by higher-kinded types

Scala is one of the few languages that have higher-kinded types; a simple feature with profound implications. This talk will explore uses of higher-kinded types and show why they are an indispensable feature.

November 11, 2016

## Transcript

1. Spoiled by
higher-kinded types
Box, Inc.

2. Values

3. Values
val i = 42
val l = List((), (), ())
val e = Right('a')

4. Values
val i = 42
val l = List((), (), ())
val e = Right('a')
// Functions
def goInt[A](int: Int): Double
def goList[A](as: List[A]): Char
def goEither[A, B](e: Either[A, B]): Byte

5. Transforming a List
def dup(l: List[String]): List[String] =
l match {
case Nil => Nil
case h :: t => (h ++ h) :: dup(t)
}

6. Transforming a List
def toInt(l: List[Char]): List[Int] =
l match {
case Nil => Nil
case h :: t => (h.toInt) :: toInt(t)
}

7. Transforming a List
def isZ(l: List[Int]): List[Boolean] =
l match {
case Nil => Nil
case h :: t => (h == 0) :: isZ(t)
}

8. Transforming a List
def map[A, B](as: List[A])(f: A => B): List[B] =
as match {
case Nil => Nil
case h :: t => f(h) :: map(as)(t)
}

9. Transforming a List
def dup(l: List[String]): List[String] =
map(l)(s => s ++ s)
def toInt(l: List[Char]): List[Int] =
map(l)(_.toInt)
def isZ(l: List[Int]): List[Boolean] =
map(l)(_ == 0)

10. Types

11. Types
// Kind *
Byte
Option[Int]
Either[String, List[Char]]

12. Types
// Kind *
Byte
Option[Int]
Either[String, List[Char]]
// Functions
List // * -> *
Either // (*, *) -> *
CanBuildFrom // (*, *, *) -> *

13. Traversing a List
def traverseFuture[A, B]
(as: List[A])
(f : A => Future[B]): Future[List[B]] =
as.foldRight(Future.successful(List.empty[B])) {
case (a, acc) =>
f(a).zip(acc).map {
case (b, bs) => b :: bs
}
}

14. Traversing a List
def traverseOption[A, B]
(as: List[A])
(f : A => Option[B]): Option[List[B]] =
as.foldRight(Some(List.empty[B]): Option[List[B]]) {
case (a, acc) =>
case (b, bs) => b :: bs
}
}

15. Traversing a List
def traverseEither[A, B, E]
(as: List[A])
(f : A => Either[E, B]): Either[E, List[B]] =
as.foldRight(Right(List()): Either[E, List[B]]) {
case (a, acc) =>
f(a).flatMap(a => acc.map(b => (a, b))).map {
case (b, bs) => b :: bs
}
}

16. Traversing a List
trait Applicative[F[_]] {
def pure[A](a: A): F[A]
def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
def map[A, B](fa: F[A])(f: A => B): F[B]
}
// (* -> *) -> *
implicit val futureAp : Applicative[Future]
implicit val optionAp : Applicative[Option]
implicit def eitherAp[E]: Applicative[Either[E, ?]]
'?' syntax is via the kind-projector compiler plugin: https://github.com/non/kind-projector

17. Traversing a List
def traverse[F[_]: Applicative, A, B]
(as: List[A])(f: A => F[B]): F[List[B]] =
as.foldRight(List.empty[B].pure[F]) {
case (a, acc) =>
f(a).product(acc).map {
case (b, bs) => b :: bs
}
}

18. Traversing a List
def traverseFuture[A, B]
(as: List[A])
(f : A => Future[B]): Future[List[B]] =
traverse(as)(f)
def traverseOption[A, B]
(as: List[A])
(f : A => Option[B]): Option[List[B]] =
traverse(as)(f)
def traverseEither[A, B, E]
(as: List[A])
(f : A => Either[E, B]): Either[E, List[B]] =
traverse[Either[E, ?], A, B](as)(f)
'?' syntax is via the kind-projector compiler plugin: https://github.com/non/kind-projector

19. Let's write some code!

20. Problems

21. def foo[F[_], A](fa: F[A]): Int = 42
val f: Function1[Int, Double] = _.toDouble
foo(f)
foo[Function1[Int, ?]] (f)
foo[Function1[?, Double]](f)
Puzzle solving
'?' syntax is via the kind-projector compiler plugin: https://github.com/non/kind-projector

22. def foo[F[_], A](fa: F[A]): Int = 42
val f: Function1[Int, Double] = _.toDouble
foo(f)
foo[Function1[Int, ?]] (f)
foo[Function1[?, Double]](f)
Puzzle solving
'?' syntax is via the kind-projector compiler plugin: https://github.com/non/kind-projector

23. def traverse[F[_]: Applicative, A, B]
(as: List[A])(f: A => F[B]): F[List[B]]
def reciprocal(i: Int): Either[String, Double] =
if (i == 0) Left("reciprocal of 0")
else Right(1.0 / i)
traverse(List(1, 2, 3))(reciprocal)
Puzzle solving
traverse[Either[String, ?], Int, Double]
traverse[Either[?, Double], Int, String]
'?' syntax is via the kind-projector compiler plugin: https://github.com/non/kind-projector

24. def traverse[F[_]: Applicative, A, B]
(as: List[A])(f: A => F[B]): F[List[B]]
def reciprocal(i: Int): Either[String, Double] =
if (i == 0) Left("reciprocal of 0")
else Right(1.0 / i)
traverse(List(1, 2, 3))(reciprocal)
Puzzle solving
traverse[Either[String, ?], Int, Double]
traverse[Either[?, Double], Int, String]
'?' syntax is via the kind-projector compiler plugin: https://github.com/non/kind-projector

25. Currying
val foo: (Int, String, Byte) => Long = ???

26. Currying
val foo: (Int, String, Byte) => Long = ???
val foo: Int => String => Byte => Long = ???

27. Currying
Either[A, B] // (*, *) -> *
Const[A, B] // (*, *) -> *
OptionT[F[_], A] // ((* -> *), *) -> *
Kleisli[F[_], A, B] // ((* -> *), *, *) -> *

28. Currying
Either[A][B] // * -> * -> *
Const[A][B] // * -> * -> *
OptionT[F[_]][A] // (* -> *) -> * -> *
Kleisli[F[_]][A][B] // (* -> *) -> * -> * -> *

29. Currying
def traverse[F[_]: Applicative, A, B]
(as: List[A])(f: A => F[B]): F[List[B]]

30. Currying
def traverse[F[_]: Applicative, A, B]
(as: List[A])(f: A => F[B]): F[List[B]]
// Either :: * -> (* -> *)
traverse[Either[String], Int, Double]

31. Currying
def traverse[F[_]: Applicative, A, B]
(as: List[A])(f: A => F[B]): F[List[B]]
// Either :: * -> (* -> *)
traverse[Either[String], Int, Double]
List[Int] =>
(Int => Either[String][Double]) =>
Either[String][List[Double]]

32. More code!

33. • Generics of a Higher Kind
• Higher-kinded types: the difference between giving
up, and moving forward
• Scala PR #5102: Add support for partial uniﬁcation
of type constructors
• Explaining Miles's Magic
• SI-2712: Implement higher-order uniﬁcation for type
constructor inference