Skip to content

Instantly share code, notes, and snippets.

@alexandru
Last active March 17, 2017 09:16
Show Gist options
  • Select an option

  • Save alexandru/e13c10adfdaef47078b3d19f843469a8 to your computer and use it in GitHub Desktop.

Select an option

Save alexandru/e13c10adfdaef47078b3d19f843469a8 to your computer and use it in GitHub Desktop.
Scala's Covariance Rules are Maybe Incompatible with Higher-Kinds :-(
import scala.language.higherKinds
sealed abstract class Stuff[F[_], +A]
case class Suspend[F[_], A](a: () => F[A])
extends Stuff[F, A]
// This function fails compilation compilation with:
//
// found : Suspend[F,?A1] where type ?A1 <: A (this is a GADT skolem)
// required: Suspend[F,A]
// Note: ?A1 <: A, but class Suspend is invariant in type A.
// You may wish to define A as +A instead. (SLS 4.5)
// case ref @ Suspend(_) => ref
// ^
def extract[F[_], A](source: Stuff[F, A]): Suspend[F, A] =
source match {
case ref @ Suspend(_) => ref
}
// Following that advice, if we declare Suspend as covariant in +A
// error: covariant type A occurs in invariant position in type => () => F[A] of value a
// final case class Suspend[F[_], +A](a: () => F[A])
// ^
//
// The solutions I'm seeing now are:
//
// 1. make F[_] covariant (i.e. F[+_]), but this will exclude
// useful F implementations from Cats / Scalaz at least
// 2. make A invariant, but this violates user expectations
// (e.g. Scala's collections are covariant)
// 3. work with `asInstanceOf` everywhere, but this is also
// pushing a lot of complexity and ugliness to the user,
// since this ADT is public - not acceptable!
//
// Anything I'm missing?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment