[英]Is there a type-class that checks for existence of at least one implicit of a type?
I have a trait Foo[T, U]
and a type-level algorithm that given an L <: HList
and a target type U
, tells me whether there exists T
in L
such that there is an implicit Foo[T, U]
in scope.我有一个特征Foo[T, U]
和一个类型级算法,它给出了一个L <: HList
和一个目标类型U
,告诉我在L
是否存在T
使得有一个隐式的Foo[T, U]
在范围。 This is implemented using the following type class:这是使用以下类型类实现的:
trait Search[L <: HList, U]
object Search {
def apply[L <: HList, U](implicit s: Search[L, U]): U = null
...
}
and we have the following:我们有以下内容:
object Test {
type L = Int :: String :: HNil
implicit val foo: Foo[String, Boolean] = null
Search[L, Boolean] //compiles
Search[L, Double] //does not compile
}
What I would like is for the search to not take place at all if there is no Foo[T, U]
for any T
at all in scope, as then we already know that the algorithm will not complete.我想要的是,如果在范围内根本没有任何T
Foo[T, U]
,则搜索根本不会发生,因为我们已经知道该算法将无法完成。 In other words, I want a type-class trait Exists[F[_]]
for which instances exist if and only if there is at least one implicit F
in scope, so the function Search.apply
instead has signature:换句话说,我想要一个类型类trait Exists[F[_]]
当且仅当作用域中至少有一个隐式F
时才存在实例,因此函数Search.apply
具有签名:
def apply[L <: HList, U](implicit ev: Exists[Foo[_, U]], s: Search[L, U]): U = null
In this case the compiler will only try to resolve s
if there is any implicit Foo
in scope.在这种情况下,编译器只会在作用域中存在任何隐式Foo
时才尝试解析s
。
Is such a type-class possible to define?这样的类型类可以定义吗? Does one already exist?一个已经存在了吗?
Try尝试
import scala.language.experimental.macros
import scala.reflect.macros.{blackbox, contexts}
trait Exists[A]
object Exists {
implicit def materialize[A]: Exists[A] = macro impl[A]
def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val context = c.asInstanceOf[contexts.Context]
val global: context.universe.type = context.universe
val analyzer: global.analyzer.type = global.analyzer
val callsiteContext = context.callsiteTyper.context
val tpA = weakTypeOf[A]
val searchResult = analyzer.inferImplicit(
tree = EmptyTree.asInstanceOf[global.Tree],
pt = tpA.asInstanceOf[global.Type],
reportAmbiguous = false,
isView = false,
context = callsiteContext,
saveAmbiguousDivergent = true,
pos = c.enclosingPosition.asInstanceOf[global.Position]
)
val isAmbiguous = callsiteContext.reporter.firstError match {
case Some(analyzer.AmbiguousImplicitTypeError(_,_)) => true
case _ => false
}
if (searchResult.isSuccess || searchResult.isAmbiguousFailure || isAmbiguous)
q"new Exists[$tpA] {}"
else c.abort(c.enclosingPosition, s"no implicit $tpA")
}
}
Test测试
// no implicit Int
// implicitly[Exists[Int]] // doesn't compile
implicit val i: Int = 1
implicitly[Exists[Int]] // compiles
implicit val i: Int = 1
implicit val i1: Int = 2
implicitly[Exists[Int]] // compiles
I guess original Search
was我猜原来的Search
是
trait Foo[U, V]
trait Search[L <: HList, V]
trait LowPrioritySearch {
implicit def tail[H, T <: HList, V](implicit search: Search[T, V]): Search[H :: T, V] = null
}
object Search extends LowPrioritySearch {
def apply[L <: HList, U](implicit s: Search[L, U]): U = null.asInstanceOf[U]
implicit def head[U, T <: HList, V](implicit foo: Foo[U, V]): Search[U :: T, V] = null
}
Now with Exists
现在与Exists
def apply[L <: HList, U](implicit ev: Exists[Foo[_, U]], s: Search[L, U]): U = null.asInstanceOf[U]
works as well也能用
Search[L, Boolean] //compiles
// Search[L, Double] //does not compile
Tested in 2.13.0在 2.13.0 中测试
libraryDependencies ++= Seq(
scalaOrganization.value % "scala-reflect" % scalaVersion.value,
scalaOrganization.value % "scala-compiler" % scalaVersion.value
)
In Scala 3, scala.util.Not
(soon to be NotGiven
?), which exists if no implicits of the given type are found, can be used for this:在 Scala 3 中,如果未找到给定类型的隐式,则存在scala.util.Not
(即将成为NotGiven
?)可用于:
implicit val b: Byte = 1
summon[Not[Not[Byte]]] //compiles
implicit val i: Int = 0
implicit val i2: Int = 2
summon[Not[Not[Int]]] //compiles
summon[Not[Not[String]]] //doesn't compile - Not[String] not found
See it in Scastie .在Scastie 中看到它。
Your Exists
typeclass can now look like this (the syntax for givens may change soon, but you get the idea):你的Exists
类型类现在看起来像这样(givens 的语法可能很快会改变,但你明白了):
@annotation.implicitNotFound("No implicit of type ${T} was found")
trait Exists[T]
object Exists {
given [T](using Not[Not[T]]) as Exists[T]
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.