Scala 타입 클래스(Type Classes)는 기존 코드를 수정하지 않고 새 타입에 동작을 추가하는 패턴이다. Haskell의 타입 클래스를 암묵적 변환(implicit)으로 구현한다.
타입 클래스 패턴 (Scala 2)
scala
// 1. 트레이트로 타입 클래스 정의
trait Show[A] {
def show(a: A): String
}
// 2. 인스턴스 구현
object Show {
implicit val intShow: Show[Int] = a => s"Int($a)"
implicit val stringShow: Show[String] = a => s"'$a'"
// 리스트용 파생 인스턴스
implicit def listShow[A](implicit ev: Show[A]): Show[List[A]] =
xs => xs.map(ev.show).mkString("[", ", ", "]")
}
// 3. 사용 (타입 클래스 문법 설탕)
def printAll[A](items: List[A])(implicit s: Show[A]): Unit =
items.foreach(x => println(s.show(x)))
printAll(List(1, 2, 3)) // Int(1), Int(2), Int(3)
Scala 3 (Dotty) - given/using
scala
trait Eq[A]:
def eql(a: A, b: A): Boolean
given Eq[Int] with
def eql(a: Int, b: Int): Boolean = a == b
given [A: Eq]: Eq[List[A]] with
def eql(xs: List[A], ys: List[A]): Boolean =
xs.length == ys.length && xs.zip(ys).forall(summon[Eq[A]].eql)
def assertEqual[A: Eq](a: A, b: A): Unit =
if summon[Eq[A]].eql(a, b) then println("같음") else println("다름")
함수자(Functor) 타입 클래스
scala
trait Functor[F[_]]:
def map[A, B](fa: F[A])(f: A => B): F[B]
given Functor[List] with
def map[A, B](fa: List[A])(f: A => B): List[B] = fa.map(f)
given Functor[Option] with
def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
관련 개념