如何在Scala中正确使用歧义隐式进行类型求反

问题描述 投票:3回答:1

最终,我想为某个特定类型T提供一个类型类的实现,为all不是T的其他类型提供另一种实现。我认为(也许是错误的)做到这一点的最简单方法是尝试通过this question中所述的含糊不清的隐式尝试类型求反。但是,如果我不小心忽略了隐式类型类声明,我的代码仍将编译(应该吗?),但由于仅使用一种实现,因此会包含错误。

这是上下文绑定的定义方式:

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]

此时,NotInInt [T]对于除Int / Nothing外的所有T均可被召唤。

scala> implicitly[NotAnInt[String]]
res3: NotAnInt[String] = $anon$1@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上下文绑定,我可以使用其实现创建类型类:

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$1@585dd35c

scala> implicit def otherIntChecker[A: NotAnInt]: IntChecker[A] = new IntChecker[A] { override def isInt = false }
otherIntChecker: [A](implicit evidence$1: NotAnInt[A])IntChecker[A]

可以按预期使用此类型的类:

scala> def printIntStatus[T: IntChecker](t: T): Unit = { println(implicitly[IntChecker[T]].isInt()) }
printIntStatus: [T](t: T)(implicit evidence$1: 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是导致此问题的原因,但我想不出解决办法。

我对这种方法为何会失败以及如何实现同一目标的替代方法感兴趣。谢谢。

scala typeclass type-systems type-level-computation
1个回答
0
投票
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 printIntStatusWithBug[T: IntChecker](t: T) = implicitly[IntChecker[T]].isInt() import IntChecker._ printIntStatusWithBug(3) printIntStatusWithBug("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()
                                               ^
© www.soinside.com 2019 - 2024. All rights reserved.