Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Spoiled by higher-kinded types

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.

Adelbert Chang

November 11, 2016
Tweet

More Decks by Adelbert Chang

Other Decks in Programming

Transcript

  1. 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
  2. Transforming a List def dup(l: List[String]): List[String] = l match

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

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

    { case Nil => Nil case h :: t => (h == 0) :: isZ(t) }
  5. 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) }
  6. 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)
  7. Types // Kind * Byte Option[Int] Either[String, List[Char]] // Functions

    List // * -> * Either // (*, *) -> * CanBuildFrom // (*, *, *) -> *
  8. 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 } }
  9. 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 } }
  10. 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 } }
  11. 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
  12. 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 } }
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. Currying val foo: (Int, String, Byte) => Long = ???

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

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

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

    F[B]): F[List[B]] // Either :: * -> (* -> *) traverse[Either[String], Int, Double]
  22. 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]]
  23. • Generics of a Higher Kind • Higher-kinded types: the

    difference between giving up, and moving forward • Scala PR #5102: Add support for partial unification of type constructors • Explaining Miles's Magic • SI-2712: Implement higher-order unification for type constructor inference Further Reading
  24. EOF