910

# 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

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)

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) => f(a).zip(acc).headOption.map { 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

21. None
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 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
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. ### 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

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

val foo: Int => String => Byte => Long = ???
28. ### Currying Either[A, B] // (*, *) -> * Const[A, B]

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

* -> * -> * OptionT[F[_]][A] // (* -> *) -> * -> * Kleisli[F[_]][A][B] // (* -> *) -> * -> * -> *
30. ### Currying def traverse[F[_]: Applicative, A, B] (as: List[A])(f: A =>

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

F[B]): F[List[B]] // Either :: * -> (* -> *) traverse[Either[String], Int, Double]
32. ### 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]]
33. None

35. ### • 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 Further Reading