### Parametric polymorphism for functions in Scala

Posted on September 18, 2016

Let’s consider a simple typeclass:

```
trait Addable[T] {
def plus(x: T, y: T): T
}
implicit object IntAddable extends Addable[Int] {
def plus(x: Int, y: Int) = x + y
}
implicit object ListAddable extends Addable[List[Int]] {
def plus(x: List[Int], y: List[Int]) = x ++ y
}
def plus[T](x: T, y: T)(implicit ev: Addable[T]) = ev.plus(x, y)
List(1, 2, 3).foldLeft(0)(plus) //> Int = 6
List(List(1), List(2), List(3)).foldLeft(List[Int]())(plus) //> List[Int] = List(1, 2, 3)
```

What happens here is called eta-expansion, and what `foldLeft`

is getting is this function (e.g. for the former case):

```
new Function2[Int, Int, Int] {
def apply(x: Int, y: Int): Int = plus[Int](x, y)
}
```

What’s wrong here? We wrap `plus`

invocation in anonymous function and effectively transfer control twice with required stack reshuffle, and it happens for every element in a collection (details here). Can we do better?

Let’s change just one line:

`def plus[T](implicit ev: Addable[T]) = (x: T, y: T) => ev.plus(x, y)`

It still works, only now we instantiate `Function2`

by calling method `plus`

once, and this function is passed to `foldLeft`

. What is lost is the ability to call `plus`

as a method (i.e. `plus(1,2)`

).