Slide 1

Slide 1 text

The Limitations of Type Classes as Subtyped Implicits Adelbert Chang Scala Symposium 2017

Slide 2

Slide 2 text

Type classes • Ad-hoc polymorphism in Haskell (Wadler and Blott 1989) • classes and instances vs. function overloading • Automatic dictionary/instance look-up (similar to implicits) • Natural tool for building up algebraic and category- theoretic vocabulary useful in functional programming

Slide 3

Slide 3 text

Type classes in Scala • Scala has the features needed to encode type classes • traits for “classes,” implicits for instances, and subtyping for specifying relationships • Used in popular open source libraries like Scalaz, Cats, Scodec, Shapeless, Argonaut, Circe, Specs2, Algebra/ Algebird/Spire, FS2…

Slide 4

Slide 4 text

Type classes in Scala trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } implicit val listFunctor: Functor[List] = new Functor[List] { def map[A, B](fa: List[A])(f: A => B): List[B] = fa match { case Nil => Nil case h :: t => f(h) :: map(f)(t) } } def void[F[_]: Functor, A](fa: F[A]): F[Unit] = implicitly[Functor[F]].map(fa)(_ => ())

Slide 5

Slide 5 text

Type classes in Scala trait Monad[F[_]] { def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] def pure[A](a: A): F[A] }

Slide 6

Slide 6 text

Type classes in Scala trait Monad[F[_]] { def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] def pure[A](a: A): F[A] def map[A, B](fa: F[A])(f: A => B): F[B] = flatMap(fa)(a => pure(f(a)) }

Slide 7

Slide 7 text

Type classes in Scala trait Monad[F[_]] extends Functor[F] { def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] def pure[A](a: A): F[A] def map[A, B](fa: F[A])(f: A => B): F[B] = flatMap(fa)(a => pure(f(a)) } def needMonad[F[_]: Monad, A](fa: F[A]): F[Unit] = .. void(fa) ..

Slide 8

Slide 8 text

Type classes in Scala trait Monad[F[_]] extends Functor[F] { .. } trait Traverse[F[_]] extends Functor[F] { .. } def traverseAndMonad[F[_]: Monad: Traverse, A] (fa: F[A]): F[Unit] = .. void(fa) .. error: ambiguous implicit values: both value evidence$2 of type Traverse[F] and value evidence$1 of type Monad[F] match expected type Functor[F] void(fa) ^

Slide 9

Slide 9 text

The subtyped implicits encoding of type classes can fail whenever the type class hierarchy branches.

Slide 10

Slide 10 text

Source: https://github.com/tpolecat/cats-infographic under CC BY-SA 4.0

Slide 11

Slide 11 text

coherency: every different valid typing derivation for a program leads to a resulting program that has the same dynamic semantics

Slide 12

Slide 12 text

Eq[A] Ord[A] Eq[List[A]] Ord[List[A]]

Slide 13

Slide 13 text

Option 1. Assume type class coherency and solve the problem of guiding the resolver up the tree. Option 2. Make the compiler/resolver type class- aware.

Slide 14

Slide 14 text

Option 1: The Scato encoding • The main problem with the subtyped implicits encoding is subtyping • Subtyping allows us to treat subclasses (e.g. Monad) as superclasses (e.g. Functor) • What if we replaced subtyping with implicit conversions? • We can still treat subclasses as superclasses • Unlike subtyping, implicit conversions can be prioritized

Slide 15

Slide 15 text

Option 1: The Scato encoding trait Functor [F[_]] { .. } trait Monad [F[_]] { def functor: Functor[F] .. } trait Traverse[F[_]] { def functor: Functor[F] .. } trait Conversions1 { implicit def m2f[F[_]: Monad]: Functor[F] = implicitly[Monad[F]].functor } trait Conversions0 extends Conversions1 { implicit def t2f[F[_]: Traverse]: Functor[F] = implicitly[Traverse[F]].functor } object Prelude extends Conversions0

Slide 16

Slide 16 text

Option 1: The Scato encoding import Prelude._ def resolves[F[_]: Monad: Traverse] = implicitly[Functor[F]]

Slide 17

Slide 17 text

Option 2: Type class-aware Scala

Slide 18

Slide 18 text

Option 2: Type class-aware Scala

Slide 19

Slide 19 text

Option 2: Type class-aware Scala • Introduce a Coherent marker trait that changes behavior of the implicit resolver • Need to make sure choice of path cannot be detected at runtime • Object#{equals, hashCode} can violate this • Introduce a parametric Any?

Slide 20

Slide 20 text

EOF