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.

Avatar for Adelbert Chang

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