0

I am working on a system of chained implicit functions, which is similar to the simplified example below. The test c1.payload == c2.payload represents a test I need to do that is not in "type-space"; I had expected that I would drop into a macro for the definition of witnessEvidence, however Scala apparently does not allow macro definitions with implicit arguments of arbitrary type (WeakTypeTag values only!), and so I am a bit stumped about how to proceed with this. The code below shows logically what I'd like to happen, however an implicit function can't conditionally produce or not produce evidence (unless it is inside a macro implementation).

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!
eje
  • 945
  • 11
  • 22
  • Are the `Capsule` values, and in particular their `payload` fields known at compile time? – Miles Sabin Nov 22 '17 at 05:00
  • 1
    The `payload` values are generated as a byproduct of chained implicit resolution (this part appears to be working fine). So it is available at compile time. But the information isn't encoded in the form of types. I'm working on an alternative where the information is encoded as HList record so implicit resolution can get its hands on it instead. – eje Nov 22 '17 at 15:15

1 Answers1

4

This would not be possible as-is, since the implicit resolution is done at compilation, while testing for value equivalence is done at runtime.

To make this work, you need to make the compiler understand values as types, so that you can ask for the type equality of the two 3s and use that to infer that capa =:= capb. To do that you can use singleton types: https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#singleton-typed-literals

If you need to do arithmetic beyond plain equality comparison, you will need to use Nat:https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/nat.scala

V-Lamp
  • 1,630
  • 10
  • 18
  • Yes, the real structures I want to compare are more complicated, which gave rise to my other, related question for an alternative solution: https://stackoverflow.com/questions/47421083/test-two-scala-shapeless-hlist-types-for-equivalence-via-implicit – eje Nov 21 '17 at 20:47