任意深函子合成的Scala隐式
我试图为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
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 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")
}