I'm trying to provide extension methods to an existing class Elem
in Scala. However, I also want the operations to be available to any M[Elem]
, as long as a Scalaz Functor
for M
is in scope. The behavior is always to apply the operation to the functor by using map
.
import scalaz._
import Scalaz._
class Elem
implicit class Ops[F[_]: Functor, A <% Elem](self: F[A]) {
def foo = self.map(_ => "bar")
}
val elem = new Elem
// TODO (nice to have): can we avoid this "explicit implicit" conversion?
implicit def idOps[A <% Elem](self: A) = new Ops[Id, A](self)
elem.foo // bar
Option(elem).foo // Some(bar)
List(elem).foo // List(bar)
I want to go further and make my extension methods available to arbitrarily deep functors, such as List[Option[Elem]]
and Option[Option[Option[Elem]]]
. I was able to write an implicit providing Ops
for the composition of two functors, but I was not able to generalize it to arbitrary nesting depths:
// TODO: can we improve this to provide arbitrarily deep functor composition?
implicit def compositeOps[F[_]: Functor, G[_]: Functor, A <% Elem](self: F[G[A]]) = {
implicit val FG = implicitly[Functor[F]].compose[G]
new Ops[({ type FG[X] = F[G[X]] })#FG, A](self)
}
List(Option(elem)).foo // List(Some(bar))
Option(List(Option(elem))).foo // doesn't compile
Is there any way to achieve this?
A
to a fixedElem
type as in the example. Is there any way to work with that and yourHelper
other than including theA => Elem
implicit as aval
in the body ofHelper
? 2) The compiler can't findHelper
instances for subclasses of the functors themselves, e.g. I cannot applyOps
to aSome
. Is there any way to lift that restriction? I am aware that this already happens with Scalaz type classes, but in my case it is particularly important to be able to do that. – Ardie