不明确的隐式值是我们想让错误在编译时存在的唯一方法吗 [英] Is ambiguous implicit value the only way we want to make the error existed in compilation time

查看:41
本文介绍了不明确的隐式值是我们想让错误在编译时存在的唯一方法吗的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

trait Foo

trait Bar extends Foo

def doStuff[T <: Foo](x: T)(implicit ev: T =!:= Foo) = x

doStuff(new Foo{}) //ambiguous implicit value
doStuff(new Bar)// successful

隐式解析发生在编译时,所以在这里我认为可能有两个具有完全相同类型的隐式值来触发模棱两可的东西.

Implicit resolution is happening on compilation time, so in here I think there may be two implicit value with exactly same type to trigger ambiguous stuff.

现在,我要在团队中引入shapeless,我的同事认为这种含糊不清的隐式并不理想,我对此没有强烈的争论.这是为了使 Scala 中的类型安全而这样做的唯一方法吗?如果是,我该怎么做才能自定义错误消息?

Right now, I am going to introduce shapeless into the team, my colleagues think this ambiguous implicit is not ideal, and I dont have strong argument about it. Is this only way to do it in order to make type safe in scala. If it is, what can I do to customize the error message ?

在无形中,我想让2个NAT的总和不等于7,我可以这样编码让编译失败.

In the shapeless, I want to make the sum of 2 NAT not equal to 7, I can code like this to make compilation fail.

def typeSafeSum[T <: Nat, W <: Nat, R <: Nat](x: T, y: W)
         (implicit sum: Sum.Aux[T, W, R], error: R =:!= _7) = x

typeSafeSum(_3, _4)

但是错误信息是不明确的隐含值,我该如何自定义错误信息?

but the error message is ambiguous implicit value, how can I customize the error message ?

推荐答案

在这个(和大多数其他)实例中,一个简单的类型类会比类型不等式测试更好.

A simple type class would be better than a type inequality test in this (and most other) instance(s).

大概想要排除 Foo 的原因是 Bar(及其兄弟)有一些 Foo 缺少的属性.如果是这种情况,那么您应该创建一个类型类来捕获这些属性,并将其作为 doStuff 的类型参数的要求.您可以使用 Scala 的 @implicitNotFound 注释使编译器错误消息在不满足该要求时更易于理解.

Presumably the reason for wanting to exclude Foo is that Bar (and its siblings) have some properties which Foo lacks. If that's the case then you should create a type class which captures those properties and make that a requirement on the type argument for doStuff. You can use Scala's @implicitNotFound annotation to make compiler error messages more comprehensible whenever that requirement isn't met.

@annotation.implicitNotFound(msg = "No Props instance for ${T}")
trait Props[T] {
  def wibble(t: T): Double
}

trait Foo
// Note no Props instance for Foo ...

trait Bar extends Foo
object Bar {
  // Props instance for Bar
  implicit def barProps: Props[Bar] = new Props[Bar] {
    def wibble(t: Bar): Double = 23.0
  }
}

def doStuff[T <: Foo](t: T)(implicit props: Props[T]) = props.wibble(t)

scala> doStuff(new Foo {})
<console>:11: error: No Props instance for Foo
              doStuff(new Foo {})
                     ^

scala> doStuff(new Bar {})
res1: Double = 23.0

如果没有任何这样的属性可以将 FooBar 区分开来,那么你应该质疑你的假设,你需要从其中排除 FoodoStuff 放在第一位.

If there aren't any such properties which distinguish Foo from Bar then you should question your supposition that you need to exclude Foo from doStuff in the first place.

如果您在项目中使用 shapeless,我会很高兴,但您应该仅将 =!:=(以及 Scala 自己的 =:=)用作最后度假村,如果有的话.

I'd be delighted if you use shapeless in your project, but you should use =!:= (and Scala's own =:=) only as a last resort, if at all.

这篇关于不明确的隐式值是我们想让错误在编译时存在的唯一方法吗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆