简体   繁体   English

scala证据参数到底是什么

[英]What precisely is a scala evidence parameter

I've been trying to find an authoritative definition of what is an evidence parameter, to no avail, for solving a case of "could not find implicit value for evidence parameter of type....".我一直试图找到什么是证据参数的权威定义,但无济于事,以解决“无法找到类型证据参数的隐式值......”的情况。 Can you please provide a very good explanation for what an evidence parameter exactly is?您能否很好地解释证据参数到底是什么?

I'll try posting my own answer, improving it later as it goes.我会尝试发布我自己的答案,稍后再进行改进。 Let us start with a motivational scenario, but you can jump to the TLDR below then come back here as needed.让我们从一个激励场景开始,但您可以跳到下面的 TLDR,然后根据需要返回此处。

In one scenario, evidence parameters can be seen as a means of enriching a class with some behavior (method/s) from outside its original definition.在一种情况下,证据参数可以看作是一种用原始定义之外的某些行为(方法)丰富类的方法。

A mild rehash of the great post at Cake Solutions :Cake Solutions上的伟大帖子的温和改写:

In case you have not already intuitively written such code before, here's a code demonstration of evidence parameters in use.如果您以前没有直观地编写过此类代码,这里有一个使用中的证据参数的代码演示。

object EvidenceExample {

  // class with no methods
  case class Bar(value: String)

  // a trait the class Bar had not implemented
  trait WithFoo[A] {
    def foo(x: A): String
  }

  // object that attaches an implementation of the trait for Bar - for methods
  // willing to play along with this kind of trait attachment - see immediately below
  implicit object MakeItFoo extends WithFoo[Bar] {
    def foo(x: Bar) = x.value
  }

  // method willing to recognize anything as having trait WithFoo, 
  // as long as it has evidence that it does - the evidence being the previous object
  def callFoo[A](thing: A)(implicit evidence: WithFoo[A]) = evidence.foo(thing)
  
  callFoo(Bar("hi")) // and it works
}

You might read that code from the bottom up to realize that a class Bar has been enriched outside its original definition.您可能会自下而上地阅读该代码,从而意识到类Bar在其原始定义之外得到了丰富。 Yet ― only functions that play along with the evidence ceremony can see it as enriched.然而——只有配合取证仪式的功能,才能丰富它。

There's very little magic going on in this pattern ― although this is a unique language feature ― the wrapper object associates the trait to Bar , and callFoo relies on that association.这种模式几乎没有什么神奇之处——尽管这是一种独特的语言特性——包装器对象将特征与Bar相关联,而callFoo依赖于该关联。

We could even write the same pattern without implicits, but then the last line, the one that calls the method, would need an extra parameter ― the economics of whether to use an implicit or not ― are entirely up to you.我们甚至可以在没有隐式的情况下编写相同的模式,但是最后一行,即调用方法的那一行,将需要一个额外的参数——是否使用隐式的经济性——完全取决于你。

You can up-sugar or down-sugar it as you wish, for example here's a minor syntax improvement:您可以根据需要对其加糖或减糖,例如,这里有一个小的语法改进:

(only the last def herein modified, and the comments removed now) def只修改了最后一个定义,现在删除了注释)

object EquivalentEvidenceExample {

  case class Bar(value: String)

  // a trait the class Bar had not implemented
  trait WithFoo[A] {
    def foo(x: A): String
  }
  
  implicit object MakeItFoo extends WithFoo[Bar] {
    def foo(x: Bar) = x.value
  }
  
  def callFoo[A:WithFoo](thing: A) = implicitly[WithFoo[A]].foo(thing) // lightly sugared syntax, frankly only more confusing
  
  callFoo(Bar("hi"))
}

And there's nothing requiring of you to name anything with the string evidence .并且不需要您使用字符串evidence命名任何内容。 The compiler just knows this is an evidence parameter by the way it is used in all these equivalent cases.编译器只是通过在所有这些等效情况下使用它的方式知道这是一个证据参数。

More generally or etymologically, borrowing from the other answer , an evidence parameter is one that "evidences" a specific property of a type, and it is required by the compiler wherever a method's signature manifests such a requirement (in the other answer, there is no evidence supplied for type Any being <:< Foo , as required by the method's signature, hence it is a case of a missing evidence).更一般地或词源上,借用另一个答案,证据参数是“证明”一种类型的特定属性的参数,无论方法的签名是否表明这种要求,编译器都需要它(在另一个答案中,有没有为Any类型提供证据<:< Foo ,正如方法签名所要求的那样,因此这是一个缺少证据的情况)。

Failure to the have an evidence object available as an implicit, will result in the famous could not find implicit value for evidence parameter of type... because the compiler knows this is part of an evidence pattern and not just a missing implicit (as much as this difference matters to you).如果没有一个证据对象作为隐式可用,将导致著名的could not find implicit value for evidence parameter of type...因为编译器知道这是证据模式的一部分,而不仅仅是一个缺失的隐式(尽可能多因为这种差异对您很重要)。

TLDR: TLDR:

Succinctly speaking, an evidence parameter for some class S is a parameter of a type T[S] (so, a parameter that is a class) that defines one or more things about S ― thus "evidencing" something about S ― that makes S eligible for extended usage by a caller, beyond the original definition of S .简而言之,某个类S的证据参数是类型T[S]的参数(因此,一个参数是一个类),它定义了关于S的一个或多个事物——因此“证明”了关于S的一些东西——使得S有资格被调用者扩展使用,超出S的原始定义。 The exact shape such a T[S] should have, is exemplified in my borrowed examples above, by implicit object MakeItFoo . T[S]应该具有的确切形状在我上面借用的示例中通过implicit object MakeItFoo了说明。

The language specification uses the term "evidence" in§7.4 Context Bounds and View Bounds :语言规范在§7.4 上下文边界和视图边界中使用术语“证据”:

A type parameter A of a method or non-trait class may also have one or more context bounds A: T .方法或非特征类的类型参数A也可能有一个或多个上下文边界A: T In this case the type parameter may be instantiated to any type S for which evidence exists at the instantiation point that S satisfies the bound T .在这种情况下,类型参数可以实例化为任何类型S ,在实例化点存在证据表明S满足边界T Such evidence consists of an implicit value with type T[S] .此类证据包含类型为T[S]的隐式值。

With this syntactic sugar you get synthetic parameters which the spec calls "evidence parameters".使用这种语法糖,您可以获得规范称为“证据参数”的合成参数。 (Note that this also covers view-bounds <% which are now deprecated). (请注意,这还包括视图边界<% ,现在已弃用)。

Since often explicitly written implicit parameters are also named evidence , I think it's valid to call any implicit parameter an "evidence" if it witnesses a specific property of a type.由于通常显式编写的隐式参数也被命名为evidence ,我认为将任何隐式参数称为“证据”是有效的,如果它见证了一个类型的特定属性。 Take for example <:< [A, B] that evidences that A is a sub-type of B :例如<:< [A, B]证明AB的子类型:

trait Foo

trait Bar[A] {
  def baz(implicit evidence: A <:< Foo): Unit
}

Then if you try this:那么如果你试试这个:

trait Test {
  def bar: Bar[Any]

  bar.baz
}

This fails with a compilation error:这会因编译错误而失败:

<console>:58: error: Cannot prove that Any <:< Foo.
         bar.baz
             ^

The exact wording can be specified with the implicitNotFound annotation .可以使用implicitNotFound注释指定确切的措辞。 Without a specific code example, it's unclear what generates the "could not find implicit value for evidence parameter of type....".如果没有具体的代码示例,则不清楚是什么生成了“无法找到类型为……的证据参数的隐式值”。

Here's an example of a custom message:以下是自定义消息的示例:

@annotation.implicitNotFound(msg = "Oh noes! No type class for ${A}")
trait MyTypeClass[A]

trait Bar[A] {
  def baz(implicit evidence: MyTypeClass[A]): Unit
}

Then:然后:

trait Test {
  def bar: Bar[Any]

  bar.baz
}

Fails with the custom message:自定义消息失败:

<console>:58: error: Oh noes! No type class for Any
         bar.baz
             ^

Scala evidence parameters are prepended to implicit parameter list. Scala 证据参数被添加到隐式参数列表中。

def foo[A: M](implicit b: B): C
// expands to:
// def foo[A](implicit evidence$1: M[A], b: B): C

See specifications for more details.有关详细信息,请参阅规格。 https://www.scala-lang.org/files/archive/spec/2.11/07-implicits.html https://www.scala-lang.org/files/archive/spec/2.11/07-implicits.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM