### 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
}

def plus(x: Int, y: Int) = x + y
}

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)`).