-
-
Save benhutchison/3984314 to your computer and use it in GitHub Desktop.
implementation of Equal typeclass using contravariance - difficulties resolved
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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