Slide 1

Slide 1 text

Spoiled by higher-kinded types Adelbert Chang @adelbertchang Box, Inc.

Slide 2

Slide 2 text

Values

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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) }

Slide 9

Slide 9 text

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)

Slide 10

Slide 10 text

Types

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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 } }

Slide 14

Slide 14 text

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 } }

Slide 15

Slide 15 text

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 } }

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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 } }

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Let's write some code!

Slide 20

Slide 20 text

Problems

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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]]

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

More code!

Slide 35

Slide 35 text

• 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

Slide 36

Slide 36 text

EOF