### sum function

Nick demonstrates an example of ad-hoc polymorphism by gradually making `sum` function more general, starting from a simple function that adds up a list of `Int`s:

``````scala> def sum(xs: List[Int]): Int = xs.foldLeft(0) { _ + _ }
sum: (xs: List[Int])Int
scala> sum(List(1, 2, 3, 4))
res2: Int = 10``````

#### Monoid

If we try to generalize a little bit. I’m going to pull out a thing called `Monoid`. … It’s a type for which there exists a function `mappend`, which produces another type in the same set; and also a function that produces a zero.

``````scala> object IntMonoid {
def mappend(a: Int, b: Int): Int = a + b
def mzero: Int = 0
}
defined object IntMonoid``````

If we pull that in, it sort of generalizes what’s going on here:

``````scala> def sum(xs: List[Int]): Int = xs.foldLeft(IntMonoid.mzero)(IntMonoid.mappend)
sum: (xs: List[Int])Int
scala> sum(List(1, 2, 3, 4))
res3: Int = 10``````

Now we’ll abstract on the type about `Monoid`, so we can define `Monoid` for any type `A`. So now `IntMonoid` is a monoid on `Int`:

``````scala> trait Monoid[A] {
def mappend(a1: A, a2: A): A
def mzero: A
}
defined trait Monoid
scala> object IntMonoid extends Monoid[Int] {
def mappend(a: Int, b: Int): Int = a + b
def mzero: Int = 0
}
defined object IntMonoid``````

What we can do is that `sum` take a `List` of `Int` and a monoid on `Int` to sum it:

``````scala> def sum(xs: List[Int], m: Monoid[Int]): Int = xs.foldLeft(m.mzero)(m.mappend)
sum: (xs: List[Int], m: Monoid[Int])Int
scala> sum(List(1, 2, 3, 4), IntMonoid)
res4: Int = 10``````

We are not using anything to do with `Int` here, so we can replace all `Int` with a general type:

``````scala> def sum[A](xs: List[A], m: Monoid[A]): A = xs.foldLeft(m.mzero)(m.mappend)
sum: [A](xs: List[A], m: Monoid[A])A
scala> sum(List(1, 2, 3, 4), IntMonoid)
res5: Int = 10``````

The final change we have to take is to make the `Monoid` implicit so we don’t have to specify it each time.

``````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\$@4138f8c0
scala> sum(List(1, 2, 3, 4))
res6: Int = 10``````

Nick didn’t do this, but the implicit parameter is often written as a context bound:

``````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))
res7: Int = 10``````

Our `sum` function is pretty general now, appending any monoid in a list. We can test that by writing another `Monoid` for `String`. I’m also going to package these up in an object called `Monoid`. The reason for that is Scala’s implicit resolution rules: When it needs an implicit parameter of some type, it’ll look for anything in scope. It’ll include the companion object of the type that you’re looking for.

``````scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Monoid[A] {
def mappend(a1: A, a2: A): A
def mzero: A
}
object Monoid {
implicit val IntMonoid: Monoid[Int] = new Monoid[Int] {
def mappend(a: Int, b: Int): Int = a + b
def mzero: Int = 0
}
implicit val StringMonoid: Monoid[String] = new Monoid[String] {
def mappend(a: String, b: String): String = a + b
def mzero: String = ""
}
}
def sum[A: Monoid](xs: List[A]): A = {
val m = implicitly[Monoid[A]]
xs.foldLeft(m.mzero)(m.mappend)
}

// Exiting paste mode, now interpreting.
defined trait Monoid
defined object Monoid
sum: [A](xs: List[A])(implicit evidence\$1: Monoid[A])A
scala> sum(List("a", "b", "c"))
res8: String = abc``````

You can still provide different monoid directly to the function. We could provide an instance of monoid for `Int` using multiplications.

``````scala> val multiMonoid: Monoid[Int] = new Monoid[Int] {
def mappend(a: Int, b: Int): Int = a * b
def mzero: Int = 1
}
multiMonoid: Monoid[Int] = \$anon\$1@3e55a968
scala> sum(List(1, 2, 3, 4))(multiMonoid)
res9: Int = 24``````