Skip to content

Instantly share code, notes, and snippets.

@benhutchison
Forked from eed3si9n/contravariant.scala
Created October 31, 2012 01:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benhutchison/3984314 to your computer and use it in GitHub Desktop.
Save benhutchison/3984314 to your computer and use it in GitHub Desktop.
implementation of Equal typeclass using contravariance - difficulties resolved
object Test extends App {
trait CanEqual[-A] {
def equals(a1: A, a2: A): Boolean
}
object CanEqual {
def apply[A](implicit ev: CanEqual[A]): CanEqual[A] = ev
def equals[A](f: (A, A) => Boolean): CanEqual[A] = new CanEqual[A] {
def equals(a1: A, a2: A): Boolean = f(a1, a2)
}
}
trait CanEqualOps[A] {
def self: A
//the key difference from Eugene's example is that resolution of the CanEqual typeclass is done on ===,
//rather than when the first operand is wrapped by CanEqualOps
//this allows us to find a type C that is least-upper-bound of A and B
final def ===[B <: C, C >: A](other: B)(implicit ev: CanEqual[C]): Boolean = ev.equals(self, other)
}
object ToCanEqualOps {
implicit def toCanEqualOps[A](v: A) =
new CanEqualOps[A] {
def self = v
}
}
sealed trait TrafficLight
case object Red extends TrafficLight
case object Yellow extends TrafficLight
case object Green extends TrafficLight
implicit val TrafficLightEqual = CanEqual.equals[TrafficLight] {_ == _}
import ToCanEqualOps._
Red === Green
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment