Type Class syntax in Scala
Coding against the typeclass:
trait Monoid[T] { def zero: T def add(a: T, b: T): T } object TypeClass { object IntSum extends Monoid[Int] { def zero = 0 def add(a: Int, b: Int): Int = a + b } object StringSum extends Monoid[String] { def zero = "" def add(a: String, b: String): String = a + b } def sum[T](xs: List[T], monoid: Monoid[T]): T = { xs.foldLeft(monoid.zero)(monoid.add) } } object Test { import TypeClass._ val sumInt: Int = sum(List(1,2,3), IntSum) val sumStr: String = sum(List("oh", "hey"), StringSum) }
Using implicit parameters makes it a lot neater:
trait Monoid[T] { def zero: T def add(a: T, b: T): T } object TypeClass { implicit object IntSum extends Monoid[Int] { def zero = 0 def add(a: Int, b: Int): Int = a + b } implicit object StringSum extends Monoid[String] { def zero = "" def add(a: String, b: String): String = a ++ b } def sum[T](xs: List[T])(implicit monoid: Monoid[T]): T = { xs.foldLeft(monoid.zero)(monoid.add) } } object Test { import TypeClass._ val sumInt: Int = sum(List(1,2,3)) val sumStr: String = sum(List("oh", "hey")) }
I can also use an implicit class if I want sum to be a method; this way the compiler will see if it can convert any List[T] into a SummableThingy that has the new summarise method defined.
trait Monoid[T] { def zero: T def add(a: T, b: T): T } object TypeClass { implicit object IntSum extends Monoid[Int] { def zero = 0 def add(a: Int, b: Int): Int = a + b } implicit object StringSum extends Monoid[String] { def zero = "" def add(a: String, b: String): String = a ++ b } def sum[T](xs: List[T])(implicit monoid: Monoid[T]): T = { xs.foldLeft(monoid.zero)(monoid.add) } implicit class SummableThingy[T](x: List[T]) { def summarize(implicit monoid: Monoid[T]): T = sum(x) } } object Test { import TypeClass._ List(1, 2, 3).summarize List("oh, hey").summarize }