scalaz.Equal用于路径依赖类型

Chi*_*rlo 5 scala scalaz path-dependent-type

我正在尝试路径依赖类型,并在尝试为其编写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
Run Code Online (Sandbox Code Playgroud)

我首先想在编译时制作b1"无与伦比的"(这是一个单词?)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 
Run Code Online (Sandbox Code Playgroud)

我的第二个实验是尝试使等同性更少限制,允许实例A#B相互比较而不是其他类型,具有:

 implicit val  BEqual: scalaz.Equal[A#B] = Equal.equalA
Run Code Online (Sandbox Code Playgroud)

但它不能按预期工作:

b1 === b2 //doesnt' compile, === is not a member of a1.B 
Run Code Online (Sandbox Code Playgroud)

但这有效:

BEqual.equal(b1,b2)  //compiles
BEqual.equal(b1,"string")   //doesnt' compile, good
Run Code Online (Sandbox Code Playgroud)

所以,我想知道为什么===不起作用,如果我可以编写一个Equal适用于所有A#Bs 的实例?

我尝试了一种带有隐式转换的家庭酿造解决方案,它起作用

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
Run Code Online (Sandbox Code Playgroud)

那么为什么这不起作用scalaz.Equal呢?

Tra*_*own 4

在您的第一个中,BEqual您说对于A#B您想要的任何子类型提供该子类型的Equal实例。当编译器看到它时,它就会找到实例,因为 的静态类型是。这使得事情按照你的预期进行。b1 ===Equal[a.B]b1a.B

\n\n

在第二个 中BEqual,您Equal仅为 定义一个实例A#B。这意味着 Evenb1 === b1无法编译,因为 的静态类型b1比 更具体A#B,并且Equal其类型参数是不变的。如果你向上转换你的值,实例将正常工作:

\n\n
scala> val ab1: A#B = b1\nab1: A#B = A$B@464ef4fa\n\nscala> val ab2: A#B = b2\nab2: A#B = A$B@2d3b749e\n\nscala> ab1 === ab2\nres1: Boolean = false\n
Run Code Online (Sandbox Code Playgroud)\n\n

在直接调用的版本中BEqual.equal,您本质上完成了相同的事情\xe2\x80\x94方法参数始终是协变的,因此当您将静态类型的内容作为 a 作为a.B参数传递时A#B,一切都会正常工作。在你的手工隐式类中,你同样只是说你想使用任何旧的A#B.

\n\n

Some(1) === Some(1)当你写vs. Option(1) === Option(1)(或some(1) === some(1))时,你可以看到同样的事情。Scalaz 提供了Equalfor Option[A: Equal],但没有 for Some[A: Equal],当第一个参数具有更具体的静态类型时,Option将找不到实例。

\n\n

这不是您想要解决的问题,因为 Scalaz 的不变性Equal是有意为之的。如果您想在此上下文中使用A#B值作为A#B值,则需要显式地向上转换它们。

\n