oxb*_*kes 4 scala type-inference typeclass
请考虑以下简单代码来创建typesafe等号.第一部分允许我Identity为任何类型创建一个类型类.
scala> trait Equals[A] { def equal(a1 : A, a2 : A) : Boolean }
defined trait Equals
scala> sealed trait Identity[A] {
| def value : A
| def ===(b : A)(implicit e : Equals[A]) = e.equal(value, b)
| }
defined trait Identity
scala> implicit def ToIdentity[A](a : A) = new Identity[A] { val value = a }
ToIdentity: [A](a: A)java.lang.Object with Identity[A]
Run Code Online (Sandbox Code Playgroud)
所以,如果我创建一个类型类Equals[Int],我现在应该可以使用我的typesafe equals:
scala> implicit val EqualsInt = new Equals[Int] { def equal(i1 : Int, i2 : Int) = i1 == i2 }
EqualsInt: java.lang.Object with Equals[Int] = $anon$1@7e199049
scala> 1 === 2
res1: Boolean = false
scala> 1 === 1
res2: Boolean = true
scala> 1 === 1D
<console>:10: error: type mismatch;
found : Double(1.0)
required: Int
1 === 1D
^
Run Code Online (Sandbox Code Playgroud)
好的,到目前为止一切顺利.如果我现在创建一个Equals[Any]会怎么样?
scala> implicit val EqualsAny = new Equals[Any] { def equal(a1 : Any, a2 : Any) = a1 == a2 }
EqualsAny: java.lang.Object with Equals[Any] = $anon$1@141d19
scala> 1 === 1D
<console>:11: error: type mismatch;
found : Double(1.0)
required: Int
1 === 1D
^
Run Code Online (Sandbox Code Playgroud)
但是如果我告诉编译器我的类型是一个Any,而不是Int...
scala> (1 : Any) === 1D
res6: Boolean = true
Run Code Online (Sandbox Code Playgroud)
所以我的问题是"为什么编译器不考虑逻辑上具有的所有类型?"
也就是说,我的理解是Int逻辑类型的引用具有类型Int,AnyVal和Any.无论如何,我进行了更多的探索,假设问题与协方差有关.我改变了我的定义Identity:
scala> sealed trait Identity[+A] {
| def value : A
| def ===[B >: A : Equals](b : B) = implicitly[Equals[B]].equal(value, b)
| }
defined trait Identity
Run Code Online (Sandbox Code Playgroud)
这次我得到了错误:
scala> 1 === 1D
<console>:10: error: could not find implicit value for evidence parameter of type Equals[AnyVal]
1 === 1D
^
Run Code Online (Sandbox Code Playgroud)
所以,如果我创建一个Equals[AnyVal],那么这也有效:
scala> implicit val EqualsAnyVal = new Equals[AnyVal] { def equal(a1 : AnyVal, a2 : AnyVal) = a1 == a2 }
EqualsAnyVal: java.lang.Object with Equals[AnyVal] = $anon$1@67ce08c7
scala> 1 === 1D
res4: Boolean = true
Run Code Online (Sandbox Code Playgroud)
所以在这里我假设问题是与非逆变性有关Equals.所以我再试一次(但没有创建Equals[AnyVal]):
scala> trait Equals[-A] { def equal(a1 : A, a2 : A) : Boolean }
defined trait Equals
scala> 1 === 1D
res3: Boolean = true
Run Code Online (Sandbox Code Playgroud)
所以,我可以看看这里有什么样的东西.但我的问题看起来像这样:为什么typer没有问这个问题(对于我的第一个例子):
Int; 有了范围内的含义,我可以创建一个Identity[Int]然后使用该===方法.但这不起作用,因为论证不是Int.再次尝试考虑1的替代类型.AnyVal; 有了范围的含义,我可以创建一个Identity[AnyVal]然后使用===.但这不起作用,因为虽然参数是一个AnyVal,但Equals[AnyVal]范围内没有隐含的.再次尝试考虑1的替代类型.Any; 有了范围的含义,我可以创建一个Identity[Any]然后使用===.这是有效的,因为参数都是一个Any并且有一个Equals[Any]范围.为什么类型推断只考虑最严格的1(即Int)类型?