Abdul Rahman Abdul Rahman - 1 month ago 7
Scala Question

What is wrong with the method definition

Below are my method signatures and definitions in scala

def accumulate[T[_]: Traversable, O: Monoid, A]: (A => O) => T[A] => O =
fao => ta =>
(implicitly[Traversable[T]].traverse[({type f[X] = Acc[O, X]})#f, A, O](ta)(a => Acc(fao(a)))).value

def reduce[T[_]: Traversable, O: Monoid]: T[O] => O = to => accumulate[T, O, O](a => a)(to)


However I get the following error for my definition of reduce

Error:(160, 82) not enough arguments for method accumulate: (implicit evidence$7: Traversable[T], implicit evidence$8: Monoid[O])(O => O) => (T[O] => O).
Unspecified value parameter evidence$8.
def reduce[T[_]: Traversable, O: Monoid]: T[O] => O = to => accumulate[T, O, O](a => a)(to)
^


Not sure where I am going wrong. Any help would be appreciated.

Thanks!

Answer

You are getting tripped up by the hidden (implicit) parameters to the accumulate method. The context bounds you've placed on it mean that the method really has the following type signature:

def accumulate[T[_], O, A](
  implicit traversable: Traversable[T],
  monoid: Monoid[O]): (A => O) => T[A] => O

In fact I'd advise you to not use context bounds if you actually do need to use their corresponding implicits in your methods (as opposed to just implicitly passing them in to another method). It's much clearer to type out the implicits explicitly (ironically).

So, what's happening in reduce is that you're trying to pass in the function a => a in the position where the compiler is expecting the two implicit arguments of Traversable[T] and Monoid[O]. The solution is to either pass in the implicits explicitly, or monomorphise accumulate before calling it:

def reduce[T[_]: Traversable, O: Monoid]: T[O] => O = { to =>
  // This forces the compiler to pass in the correct implicits
  val accumulate_ = accumulate[T, O, O]
  accumulate_(a => a)(to)
}