如何在 Scala 中正确使用不明确的隐式类型否定
How to correctly use ambiguous implicits for type negation in Scala
最终我想做的是为某些特定类型 T
提供一种类型 class 的实现,并为 all 其他类型提供另一种实现不是 T
。我认为(也许是错误的)最简单的方法是通过 中描述的模糊隐式来尝试类型否定。但是,如果我不小心省略了隐式类型 class 声明,我的代码仍然可以编译(应该吗?)但包含错误,因为只使用了一个实现。
上下文绑定是这样定义的:
scala> trait NotAnInt[A]
defined trait NotAnInt
scala> implicit def everythingIsNotAnInt[A]: NotAnInt[A] = new NotAnInt[A] {}
everythingIsNotAnInt: [A]=> NotAnInt[A]
scala> implicit def intsAreInts1: NotAnInt[Int] = ???
intsAreInts1: NotAnInt[Int]
scala> implicit def intsAreInts2: NotAnInt[Int] = ???
intsAreInts2: NotAnInt[Int]
scala> implicit def nothingsAreInts1: NotAnInt[Nothing] = ???
nothingsAreInts1: NotAnInt[Nothing]
scala> implicit def nothingsAreInts2: NotAnInt[Nothing] = ???
nothingsAreInts2: NotAnInt[Nothing]
此时 NotAnInt[T] 对除 Int/Nothing 之外的所有 T 都是可召唤的:
scala> implicitly[NotAnInt[String]]
res3: NotAnInt[String] = $anon@1a24fe09
scala> implicitly[NotAnInt[Int]]
<console>:16: error: ambiguous implicit values:
both method intsAreInts1 of type => NotAnInt[Int]
and method intsAreInts2 of type => NotAnInt[Int]
match expected type NotAnInt[Int]
implicitly[NotAnInt[Int]]
^
scala> implicitly[NotAnInt[Nothing]]
<console>:18: error: ambiguous implicit values:
both method nothingsAreInts1 of type => NotAnInt[Nothing]
and method nothingsAreInts2 of type => NotAnInt[Nothing]
match expected type NotAnInt[Nothing]
implicitly[NotAnInt[Nothing]]
^
现在我定义了 NotAnInt
上下文绑定,我可以创建我的类型 class 及其实现:
scala> trait IntChecker[A] { def isInt(): Boolean }
defined trait IntChecker
scala> implicit val intIntChecker: IntChecker[Int] = new IntChecker[Int] { override def isInt = true }
intIntChecker: IntChecker[Int] = $anon@585dd35c
scala> implicit def otherIntChecker[A: NotAnInt]: IntChecker[A] = new IntChecker[A] { override def isInt = false }
otherIntChecker: [A](implicit evidence: NotAnInt[A])IntChecker[A]
这个类型class可以按预期使用:
scala> def printIntStatus[T: IntChecker](t: T): Unit = { println(implicitly[IntChecker[T]].isInt()) }
printIntStatus: [T](t: T)(implicit evidence: IntChecker[T])Unit
scala> printIntStatus(3)
true
scala> printIntStatus("three")
false
但是,以下也编译:
scala> def printIntStatusWithBug[T](t: T): Unit = { println(implicitly[IntChecker[T]].isInt()) }
printIntStatusWithBug: [T](t: T)Unit
scala> printIntStatusWithBug(3)
false
scala> printIntStatusWithBug("three")
false
我不希望第二个函数可以编译,因为应该没有可用的隐式 IntChecker[T]
。我预计 everythingIsNotAnInt
是导致此问题的原因,但我想不出解决此问题的方法。
我对这种方法失败的原因以及实现相同目标的替代方法很感兴趣。谢谢。
考虑以下替代实现(使用 Sabin 的 type inequalities)
trait =!=[A, B]
implicit def neq[A, B] : A =!= B = null
implicit def neqAmbig1[A] : A =!= A = null
implicit def neqAmbig2[A] : A =!= A = null
trait IntChecker[A] {
def isInt(): Boolean
}
object IntChecker {
import scala.reflect.ClassTag
implicit val intIntChecker: IntChecker[Int] = () => true
implicit def notIntIntChecker[T: ClassTag](implicit ev: T =!= Int): IntChecker[T] = () => false
}
def printIntStatus[T: IntChecker](t: T) = implicitly[IntChecker[T]].isInt()
import IntChecker._
printIntStatus(3)
printIntStatus("three")
输出
res0: Boolean = true
res1: Boolean = false
然而,我们忘记 IntChecker
绑定的错误实现
def printIntStatusWithBug[T](t: T) = implicitly[IntChecker[T]].isInt()
不应编译,因为 T: ClassTag
绑定在
中
implicit def notIntIntChecker[T: ClassTag](implicit ev: T =!= Int)
给出编译器错误
could not find implicit value for parameter e: IntChecker[T]
def printIntStatusWithBug[T](t: T) = implicitly[IntChecker[T]].isInt()
^
最终我想做的是为某些特定类型 T
提供一种类型 class 的实现,并为 all 其他类型提供另一种实现不是 T
。我认为(也许是错误的)最简单的方法是通过
上下文绑定是这样定义的:
scala> trait NotAnInt[A]
defined trait NotAnInt
scala> implicit def everythingIsNotAnInt[A]: NotAnInt[A] = new NotAnInt[A] {}
everythingIsNotAnInt: [A]=> NotAnInt[A]
scala> implicit def intsAreInts1: NotAnInt[Int] = ???
intsAreInts1: NotAnInt[Int]
scala> implicit def intsAreInts2: NotAnInt[Int] = ???
intsAreInts2: NotAnInt[Int]
scala> implicit def nothingsAreInts1: NotAnInt[Nothing] = ???
nothingsAreInts1: NotAnInt[Nothing]
scala> implicit def nothingsAreInts2: NotAnInt[Nothing] = ???
nothingsAreInts2: NotAnInt[Nothing]
此时 NotAnInt[T] 对除 Int/Nothing 之外的所有 T 都是可召唤的:
scala> implicitly[NotAnInt[String]]
res3: NotAnInt[String] = $anon@1a24fe09
scala> implicitly[NotAnInt[Int]]
<console>:16: error: ambiguous implicit values:
both method intsAreInts1 of type => NotAnInt[Int]
and method intsAreInts2 of type => NotAnInt[Int]
match expected type NotAnInt[Int]
implicitly[NotAnInt[Int]]
^
scala> implicitly[NotAnInt[Nothing]]
<console>:18: error: ambiguous implicit values:
both method nothingsAreInts1 of type => NotAnInt[Nothing]
and method nothingsAreInts2 of type => NotAnInt[Nothing]
match expected type NotAnInt[Nothing]
implicitly[NotAnInt[Nothing]]
^
现在我定义了 NotAnInt
上下文绑定,我可以创建我的类型 class 及其实现:
scala> trait IntChecker[A] { def isInt(): Boolean }
defined trait IntChecker
scala> implicit val intIntChecker: IntChecker[Int] = new IntChecker[Int] { override def isInt = true }
intIntChecker: IntChecker[Int] = $anon@585dd35c
scala> implicit def otherIntChecker[A: NotAnInt]: IntChecker[A] = new IntChecker[A] { override def isInt = false }
otherIntChecker: [A](implicit evidence: NotAnInt[A])IntChecker[A]
这个类型class可以按预期使用:
scala> def printIntStatus[T: IntChecker](t: T): Unit = { println(implicitly[IntChecker[T]].isInt()) }
printIntStatus: [T](t: T)(implicit evidence: IntChecker[T])Unit
scala> printIntStatus(3)
true
scala> printIntStatus("three")
false
但是,以下也编译:
scala> def printIntStatusWithBug[T](t: T): Unit = { println(implicitly[IntChecker[T]].isInt()) }
printIntStatusWithBug: [T](t: T)Unit
scala> printIntStatusWithBug(3)
false
scala> printIntStatusWithBug("three")
false
我不希望第二个函数可以编译,因为应该没有可用的隐式 IntChecker[T]
。我预计 everythingIsNotAnInt
是导致此问题的原因,但我想不出解决此问题的方法。
我对这种方法失败的原因以及实现相同目标的替代方法很感兴趣。谢谢。
考虑以下替代实现(使用 Sabin 的 type inequalities)
trait =!=[A, B]
implicit def neq[A, B] : A =!= B = null
implicit def neqAmbig1[A] : A =!= A = null
implicit def neqAmbig2[A] : A =!= A = null
trait IntChecker[A] {
def isInt(): Boolean
}
object IntChecker {
import scala.reflect.ClassTag
implicit val intIntChecker: IntChecker[Int] = () => true
implicit def notIntIntChecker[T: ClassTag](implicit ev: T =!= Int): IntChecker[T] = () => false
}
def printIntStatus[T: IntChecker](t: T) = implicitly[IntChecker[T]].isInt()
import IntChecker._
printIntStatus(3)
printIntStatus("three")
输出
res0: Boolean = true
res1: Boolean = false
然而,我们忘记 IntChecker
绑定的错误实现
def printIntStatusWithBug[T](t: T) = implicitly[IntChecker[T]].isInt()
不应编译,因为 T: ClassTag
绑定在
implicit def notIntIntChecker[T: ClassTag](implicit ev: T =!= Int)
给出编译器错误
could not find implicit value for parameter e: IntChecker[T]
def printIntStatusWithBug[T](t: T) = implicitly[IntChecker[T]].isInt()
^