scala/basic
sealed trait typeclass
wefree
2022. 3. 29. 14:45
문제
sealed trait 대상으로 typeclass 를 정의할 때, 다음과 같은 문제가 있다.
https://www.reddit.com/r/scala/comments/96woxd/how_to_implement_an_adt_that_all_members_have/
코드
http://eed3si9n.com/herding-cats/typeclasses-102.html 참고
trait Eq[A] {
def eqv(x: A, y: A): Boolean
}
object Eq {
def apply[A](implicit eq: Eq[A]): Eq[A] = eq
implicit class EqSyntax[A](x: A) {
def ===(y: A)(implicit eq: Eq[A]): Boolean = eq.eqv(x, y)
}
}
sealed trait TrafficLight
object TrafficLight {
def red: TrafficLight = Red
def yellow: TrafficLight = Yellow
def green: TrafficLight = Green
case object Red extends TrafficLight
case object Yellow extends TrafficLight
case object Green extends TrafficLight
}
object MyTest {
def main(args: Array[String]): Unit = {
implicit val trafficLightEq: Eq[TrafficLight] = new Eq[TrafficLight] {
override def eqv(x: TrafficLight, y: TrafficLight): Boolean = x == y
}
import Eq._
TrafficLight.Red === TrafficLight.Yellow // ERROR !!!
TrafficLight.red === TrafficLight.yellow // OK
}
}
설명
TrafficLight.Red === TrafficLight.Yellow 일 때, ERROR 인 것은 implicit Eq[TrafficLight] 가 정의되었지만, implicit Eq[TrafficLight.Red] 는 정의되지 않은 상태이기 때문이다. 그래서 TrafficeLight.Red 를 TrafficLight 타입으로 처리할 수 있도록 def red: TrafficLight = Red 로 helper function 을 정의해 사용했다. http://eed3si9n.com/herding-cats/typeclasses-102.html 에도 잘 설명이 되어있다. 이런 번거로움 때문인지 zio-prelude Equal 에서는 contravariant 타입인 Equal[-A] 로 정의했다.