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
}