任意深函子合成的Scala隐式

任意深函子合成的Scala隐式,scala,scalaz,Scala,Scalaz,我试图为Scala中现有的类Elem提供扩展方法。但是,我还希望操作对任何M[Elem]都可用,只要M的ScalazFunctor在范围内。行为总是使用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 E

我试图为Scala中现有的类
Elem
提供扩展方法。但是,我还希望操作对任何
M[Elem]
都可用,只要
M
的Scalaz
Functor
在范围内。行为总是使用
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)

有什么方法可以实现这一点吗?

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

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

我们可以创造一种特质来代表你想要的

trait DeepFunctor[X, A] {
  type Result[_]
  def map[B](x: X)(f: A => B): Result[B]
}
请注意,它允许将
X
映射到
结果[B]
<此时,code>X可以是任何东西

最简单的版本是我们说
X
等于
A
。结果应该是
Id[B]
。它被放在一个特征中,以确保它的优先级较低

trait LowerPriorityDeepFunctor {
  implicit def identity[A] =
    new DeepFunctor[A, A] {
      type Result[x] = Id[x]
      def map[B](x: A)(f: A => B) = f(x)
    }
}
请注意,不需要请求
Id
Functor

更复杂的版本是
X
是定义了
Functor
的容器

object DeepFunctor extends LowerPriorityDeepFunctor {
  implicit def deep[F[_], X, A](
    implicit F: Functor[F], inner: DeepFunctor[X, A]) =
    new DeepFunctor[F[X], A] {
      type Result[x] = F[inner.Result[x]]
      def map[B](x: F[X])(f: A => B) = F.map(x)(inner.map(_)(f))
    }
}
deep
方法的结果是
DeepFunctor
用于
F[X]
。由于我们对
X
一无所知,我们请求
X
使用
DeepFunctor
。这将递归搜索
DeepFunctor
实例,直到它达到
identity

您的
Ops
类现在变得相对简单

implicit class Ops[X](self: X) {
  def foo[A](implicit F: DeepFunctor[X, A]) = F.map(self)(_ => "bar")
}

请注意,
\uu
现在是
A
类型。如果要限制为某一类型,可以将
a
定义为
a SomeType
。如果要将
A
设置为特定类型,可以删除
A
并将
SomeType
直接放入
DeepFunctor
中。

这看起来是一个干净且相对容易理解的解决方案!唯一让我有点困扰的是,我必须在每个方法中请求一个隐式的
DeepFunctor
,而不是在类本身中,因为我有很多像
foo
这样的操作,而且我必须更改它们的所有签名。我试图将
A
F
移动到类签名,但没有成功,因为每个方法的结果都是类型依赖于
DeepFunctor
,客户端代码无法将其类型解析为原始functor组合。你觉得我有什么办法可以避免吗?如果不是这样的话:)@RuiGonçalves是的,问题似乎是由
键入Result[x]=F[inner.Result[x]]
引起的。我认为这是一个编译器错误,但我不确定。如果隐式被移动到类本身,则
结果[x]
类型将丢失。我尝试将
结果
类型移动到
深度函子[X,A,R[\u]]]
中,但这打乱了隐式解析。理论上,这本身就是一个堆栈溢出问题。不过,我没有时间创建一个简单的可复制示例来说明这个问题。感谢您的回复!我发现您的解决方案存在两个问题:1)我确实需要从
A
隐式转换为固定
Elem
类型,如示例中所示。除了将
A=>Elem
隐式地作为
val
包含在
Helper
的主体中之外,还有什么方法可以使用它和您的
Helper
吗?2) 编译器找不到functor自身子类的
Helper
实例,例如,我无法将
Ops
应用于
某些
。有没有办法解除这一限制?我知道Scalaz类型的类已经发生了这种情况,但在我的例子中,能够做到这一点尤为重要。1)
Elem
;我已将其添加到示例中的compositeOps中。2) 这真的不可能;这是scalaz中正在进行的一场辩论,但如果我们宣布事物是协变量/逆变变量,那么这将导致推断出
Any
,而不是什么应该是类型错误。可以声明一个
函子[Some]
,但这可能会给您带来麻烦。推荐的方法是使用“智能构造函数”,如scalaz的
some
,返回适当的类型(在本例中是
Option[A]
,而不是
some[A]
)。我知道

implicit class Ops[X](self: X) {
  def foo[A](implicit F: DeepFunctor[X, A]) = F.map(self)(_ => "bar")
}