I\'ve been reading up on type classes in Scala and thought I had a good grasp on it, until I remembered Java\'s java.util.Comparator
.
If I understand proper
I prefer not to talk specifically about type classes but about the type class pattern in Scala; the reason is that when you start asking "what is the type class", you end up concluding that it is just an interface used in a particular way.
(In Haskell it makes more sense to call a specific construct a type class.)
The type class pattern consists of three essential parts (but there are usually a couple more for convenience). The first is an interface parameterized by a single type that abstracts some sort of capability on the parameterized type. java.util.Comparator
is a perfect example: it provides an interface for comparison. Let's just use that.
The second thing you need is a method that makes use of that parameterization, which you can specify with short-hand notation in Scala:
// Short signature
// v------------------- "We must be able to find a Comparator for A"
def ordered[A: java.util.Comparator](a0: A, a1: A, a2: A) = {
val cmp = implicitly[java.util.Comparator[A]] // This is the Comparator
cmp.compare(a0, a1) <= 0 && cmp.compare(a1, a2) <= 0
}
// Long signature version
def ordered[A](a0: A, a1: A, a2: A)(implicit cmp: java.util.Comparator[A]) = {
cmp.compare(a0, a1) <= 0 && cmp.compare(a1, a2) <= 0
}
Okay, but where do you get that comparator from? That's the third necessary piece. By default, Scala doesn't give you Comparator
s for the classes you might like, but you can define your own:
implicit object IntComp extends java.util.Comparator[Int] {
def compare(a: Int, b: Int) = a.compareTo(b)
}
scala> ordered(1,2,3)
res5: Boolean = true
scala> ordered(1,3,2)
res6: Boolean = false
Now that you've provided the functionality for Int
(implicitly), the compiler will fill in the implicit parameter to ordered
to make it work. If you haven't yet provided the functionality, it gives an error:
scala> ordered("fish","wish","dish")
:12: error: could not find implicit value
for parameter cmp: java.util.Comparator[String]
ordered("fish","wish","dish")
until you supply that functionality:
implicit object StringComp extends java.util.Comparator[String] {
def compare(a: String, b: String) = a.compareTo(b)
}
scala> ordered("fish","wish","dish")
res11: Boolean = false
So, do we call java.util.Comparator
a type class? It certainly functions just as well as a Scala trait that handles the equivalent part of the type class pattern. So even though the type class pattern doesn't work as well in Java (since you have to explicitly specify the instance to use instead of having it implicitly looked up), from a Scala perspective java.util.Comparator
is as much a type class as anything.