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
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.
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:
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. 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.
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)
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
. 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).
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).
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
. The exact shape such a T[S]
should have, is exemplified in my borrowed examples above, by implicit object MakeItFoo
.