我正在尝试为ElemScala中的现有类提供扩展方法.但是,我也希望任何操作都可用M[Elem],只要Scalaz Functorfor M在范围内.行为总是通过使用将操作应用于仿函数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)
Run Code Online (Sandbox Code Playgroud)
我想进一步让我的扩展方法可用于任意深度的仿函数,例如List[Option[Elem]]和Option[Option[Option[Elem]]].我能够为Ops两个仿函数的组合写一个隐含的提供,但是我无法将它推广到任意嵌套深度:
// 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
Run Code Online (Sandbox Code Playgroud)
有没有办法实现这个目标?
您可以递归地使用隐式助手:
sealed trait Helper[FA] {
type A
type F[_]
def w(fa: FA): F[A]
val f: Functor[F]
}
trait Helper1 {
implicit def nil[A] = new Helper[A] {
type A = A
type F[X] = X
def w(a: A) = a
val f = implicitly[Functor[Id]]
}
}
object Helper extends Helper1 {
implicit def cons[FA1, RA](implicit u: Unapply[Functor, FA1]{type A = RA},
rest: Helper[RA]) = new Helper[FA1] {
type A = rest.A
type F[X] = u.M[rest.F[X]]
def w(fa: FA1) = u.TC.map(u.apply(fa))(rest.w)
val f = rest.f.compose(u.TC) //or the other way around, I can never remember
}
}
implicit def compositeOps[FA, A1](self: FA)(
implicit helper: Helper[FA]{type A = A1}, conv: A1 => Elem) = {
implicit val FG = helper.f
new Ops[helper.F, helper.A](helper.w(self))
}
Run Code Online (Sandbox Code Playgroud)