Scala隐含了任意深度的Functor组合

Rui*_*ves 8 scala scalaz

我正在尝试为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)

有没有办法实现这个目标?

lmm*_*lmm 3

您可以递归地使用隐式助手:

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)