scalaz.Equal 路径相关类型
scalaz.Equal for path dependent types
我正在试验依赖于路径的类型,我 运行 在尝试为其编写 scalaz.Equal
实例时遇到了问题。我有以下结构:
class A {
class B
}
val a1 = new A
val b1 = new a1.B // type a1.B
val a2 = new A
val b2 = new a2.B //type a2.B
我首先想在编译时将 b1
"unequalable"(这是一个词吗?)变为 b2
,我通过以下实现:
import scalaz._
import Scalaz._
implicit def BEqual[X <: A#B]: scalaz.Equal[X] = Equal.equalA
b1 === b1 //true
b1 === b2 // doesn't compile, good
b2 === b1 // doesn't compile, good
我的第二个实验是尝试减少相等性的限制,允许 A#B
的实例相互比较,但不能与其他类型进行比较,其中:
implicit val BEqual: scalaz.Equal[A#B] = Equal.equalA
但它没有按预期工作:
b1 === b2 //doesnt' compile, === is not a member of a1.B
然而这有效:
BEqual.equal(b1,b2) //compiles
BEqual.equal(b1,"string") //doesnt' compile, good
所以,我想知道为什么 ===
不起作用,我是否可以编写一个适用于所有 A#B
的 Equal
实例?
我尝试了一种带有隐式转换的家庭酿造解决方案,它奏效了。
implicit class abEqual(ab: A#B) {
def eqab(ab2: A#B) = ab == ab2
}
b1.eqab(b2) //ok
b2.eqab(b1) //ok
b1.eqab("String") //doesn't compile, good
那么为什么这不适用于 scalaz.Equal
?
在您的第一个 BEqual
中,您是说对于 A#B
的任何子类型,您想为该子类型提供一个 Equal
实例 .当编译器看到 b1 ===
时,它会找到 Equal[a.B]
实例,因为 b1
的静态类型是 a.B
。这会让事情如您所愿。
在您的第二个 BEqual
中,您只为 A#B
定义了一个 Equal
实例。这意味着即使 b1 === b1
也无法编译,因为 b1
的静态类型比 A#B
更具体,而 Equal
在其类型参数方面是不变的。如果您向上转换您的值,该实例将正常工作:
scala> val ab1: A#B = b1
ab1: A#B = A$B@464ef4fa
scala> val ab2: A#B = b2
ab2: A#B = A$B@2d3b749e
scala> ab1 === ab2
res1: Boolean = false
在你直接调用 BEqual.equal
的版本中,你基本上完成了同样的事情——方法参数总是协变的,所以当你将静态类型为 a.B
的东西作为 A#B
参数,一切都会正常工作。在你的手动隐式 class 中,你同样只是说你想使用任何旧的 A#B
.
当你写 Some(1) === Some(1)
与 Option(1) === Option(1)
(或 some(1) === some(1)
)时,你会看到同样的事情。 Scalaz 为 Option[A: Equal]
提供了 Equal
,但不为 Some[A: Equal]
提供,当第一个参数具有更具体的静态类型时,将找不到 Option
实例。
这不是您想要解决的问题,因为 Scalaz 的 Equal
的不变性是有意为之的。如果您想在此上下文中将 A#B
值用作 A#B
值,则需要明确地向上转换它们。
我正在试验依赖于路径的类型,我 运行 在尝试为其编写 scalaz.Equal
实例时遇到了问题。我有以下结构:
class A {
class B
}
val a1 = new A
val b1 = new a1.B // type a1.B
val a2 = new A
val b2 = new a2.B //type a2.B
我首先想在编译时将 b1
"unequalable"(这是一个词吗?)变为 b2
,我通过以下实现:
import scalaz._
import Scalaz._
implicit def BEqual[X <: A#B]: scalaz.Equal[X] = Equal.equalA
b1 === b1 //true
b1 === b2 // doesn't compile, good
b2 === b1 // doesn't compile, good
我的第二个实验是尝试减少相等性的限制,允许 A#B
的实例相互比较,但不能与其他类型进行比较,其中:
implicit val BEqual: scalaz.Equal[A#B] = Equal.equalA
但它没有按预期工作:
b1 === b2 //doesnt' compile, === is not a member of a1.B
然而这有效:
BEqual.equal(b1,b2) //compiles
BEqual.equal(b1,"string") //doesnt' compile, good
所以,我想知道为什么 ===
不起作用,我是否可以编写一个适用于所有 A#B
的 Equal
实例?
我尝试了一种带有隐式转换的家庭酿造解决方案,它奏效了。
implicit class abEqual(ab: A#B) {
def eqab(ab2: A#B) = ab == ab2
}
b1.eqab(b2) //ok
b2.eqab(b1) //ok
b1.eqab("String") //doesn't compile, good
那么为什么这不适用于 scalaz.Equal
?
在您的第一个 BEqual
中,您是说对于 A#B
的任何子类型,您想为该子类型提供一个 Equal
实例 .当编译器看到 b1 ===
时,它会找到 Equal[a.B]
实例,因为 b1
的静态类型是 a.B
。这会让事情如您所愿。
在您的第二个 BEqual
中,您只为 A#B
定义了一个 Equal
实例。这意味着即使 b1 === b1
也无法编译,因为 b1
的静态类型比 A#B
更具体,而 Equal
在其类型参数方面是不变的。如果您向上转换您的值,该实例将正常工作:
scala> val ab1: A#B = b1
ab1: A#B = A$B@464ef4fa
scala> val ab2: A#B = b2
ab2: A#B = A$B@2d3b749e
scala> ab1 === ab2
res1: Boolean = false
在你直接调用 BEqual.equal
的版本中,你基本上完成了同样的事情——方法参数总是协变的,所以当你将静态类型为 a.B
的东西作为 A#B
参数,一切都会正常工作。在你的手动隐式 class 中,你同样只是说你想使用任何旧的 A#B
.
当你写 Some(1) === Some(1)
与 Option(1) === Option(1)
(或 some(1) === some(1)
)时,你会看到同样的事情。 Scalaz 为 Option[A: Equal]
提供了 Equal
,但不为 Some[A: Equal]
提供,当第一个参数具有更具体的静态类型时,将找不到 Option
实例。
这不是您想要解决的问题,因为 Scalaz 的 Equal
的不变性是有意为之的。如果您想在此上下文中将 A#B
值用作 A#B
值,则需要明确地向上转换它们。