Ad-hoc polymorphism - type classes

424 views Asked by At

I had a look at the scalaz tutorial.

From this link, I understand the following code:

scala> def sum[A](xs: List[A])(implicit m: Monoid[A]): A = xs.foldLeft(m.mzero)(m.mappend)
sum: [A](xs: List[A])(implicit m: Monoid[A])A

scala> implicit val intMonoid = IntMonoid
intMonoid: IntMonoid.type = IntMonoid$@3387dfac

scala> sum(List(1, 2, 3, 4))
res9: Int = 10

But I dont understand the following code:

scala> def sum[A: Monoid](xs: List[A]): A = {
         val m = implicitly[Monoid[A]]
         xs.foldLeft(m.mzero)(m.mappend)
       }
sum: [A](xs: List[A])(implicit evidence$1: Monoid[A])A

scala> sum(List(1, 2, 3, 4))
res10: Int = 10

If we consider List(1, 2, 3, 4), A is an Int.

So how can we have A an Monoid and A an Int in def sum[A: Monoid](xs: List[A]): A = { ?

Thank you

1

There are 1 answers

0
Daniel C. Sobral On BEST ANSWER

The syntax A : X is called a "context bound", and it is equivalent to receiving an implicit parameter of the type X[A]. That is, the following two declarations are the same:

def sum[A: Monoid](xs: List[A]): A
def sum[A](xs: List[A])(implicit $ev0: Monoid[A]): A

However, the name of the implicit parameter is not available when using context bounds, so you need to "retrieve" it if you need to use it directly. One way to do that is using the implicitly method, as seen:

val m = implicitly[Monoid[A]]

Here's the definition of implicitly:

def implicitly[T](implicit v: T): T = v

Anyway, the two definitions you have shown are pretty much the same. If you understand the first one, just know that the second one is identical, but written with a different syntax.

A final note about context bounds: it might seem silly to use the context bound syntax just to use implicitly afterwards to get the name of the parameter. But if you just need the implicit parameter to pass as an implicit to other methods -- and, therefore, don't need to know the name --, it makes the declarations much neater.