How can I customize Scala ambiguous implicit errors when using shapeless type inequalities

。_饼干妹妹 提交于 2019-12-05 15:12:48
Miles Sabin

shapeless's =:!= (and similar type inequality operators) inherently exploit ambiguous implicits to encode Prolog-style negation as failure. And, as you've observed, Scala doesn't have a mechanism which allows library authors to provide more meaningful error messages when ambiguity is expected. Perhaps it should, or perhaps Scala should provide a more direct representation of the negation of a type making this encoding unnecessary.

Given that you've couched the question in terms of Nats I think it's probably reasonable that you're trying to work with type inequality. If it weren't Nats my recommendation in answer to another question that a type class directly encoding the relation of interest would apply here too. As it is though, I recommend that same solution as a workaround for not being able to provide better error messages.

import shapeless._, nat._, ops.nat._

@annotation.implicitNotFound(msg = "${A} + ${B} = ${N}")
trait SumNotN[A <: Nat, B <: Nat, N <: Nat]
object SumNotN {
  implicit def sumNotN[A <: Nat, B <: Nat, R <: Nat, N <: Nat]
    (implicit sum: Sum.Aux[A, B, R], error: R =:!= N): SumNotN[A, B, N] =
      new SumNotN[A, B, N] {}     
}

def typeSafeSum[T <: Nat, W <: Nat](x: T, y: W)
  (implicit valid: SumNotN[T, W, _7]) = x

scala> typeSafeSum(_3, _4)
<console>:20: error: shapeless.nat._3 + shapeless.nat._4 = shapeless.nat._7
              typeSafeSum(_3, _4)
                         ^

The technique (hiding an expected ambiguous implicit behind an implicit we expect to be not found in the case of underlying ambiguity) is generally applicable, but is obviously fairly heavyweight ... another reason why type inequalities should be avoided if at all possible.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!