在 Scala 中有条件地生成隐式

Conditionally generating implicits in scala

我正在开发一个链式隐式函数系统,它类似于下面的简化示例。测试 c1.payload == c2.payload 表示我需要做的测试不在 "type-space" 中;我原以为我会放入一个宏来定义 witnessEvidence,但是 Scala 显然不允许带有任意类型隐式参数的宏定义(仅限 WeakTypeTag 值!),所以我有点困惑如何继续这个。下面的代码在逻辑上显示了我想要发生的事情,但是隐式函数不能有条件地产生或不产生证据(除非它在宏实现中)。

case class Capsule[T](payload: Int)

trait A
trait B
trait C

implicit val capa = Capsule[A](3)
implicit val capb = Capsule[B](3)
implicit val capc = Capsule[C](7)

case class Evidence[T1, T2](e: Int)

implicit def witnessEvidence[T1, T2](implicit c1: Capsule[T1], c2: Capsule[T2]): Evidence[T1, T2] = {
  if (c1.payload == c2.payload)
    Evidence[T1, T2](c1.payload)
  else
    // Do not produce the evidence
}

def foo[T1, T2](implicit ev: Evidence[T1, T2]) = ev.e

val f1 = foo[A, B] // this should compile
val f2 = foo[A, C] // this should fail with missing implicit!

这是不可能的,因为隐式解析是在编译时完成的,而值等价性测试是在运行时完成的。

要实现这一点,您需要让编译器将值理解为类型,这样您就可以要求两个 3 的类型相等,并使用它来推断 capa =:= capb。为此,您可以使用单例类型:https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#singleton-typed-literals

如果你需要做超越普通相等比较的算术运算,你需要使用Nat:https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/nat.scala