是否有一个类型类可以检查至少一个类型的隐式是否存在?



我有一个特征Foo[T, U]和一个类型级算法,它给定一个L <: HList和一个目标类型U,告诉我L中是否存在T,以至于范围中存在隐式Foo[T, U]。这是使用以下类型类实现的:

trait Search[L <: HList, U]
object Search {
def apply[L <: HList, U](implicit s: Search[L, U]): U = null
...
}

我们有以下内容:

object Test {
type L = Int :: String :: HNil
implicit val foo: Foo[String, Boolean] = null
Search[L, Boolean] //compiles
Search[L, Double] //does not compile
}

我希望的是,如果范围内根本没有任何TFoo[T, U],则根本不进行搜索,因为那时我们已经知道算法将无法完成。换句话说,我想要一个类型类trait Exists[F[_]]当且仅当作用域中至少有一个隐式F时,实例存在,因此函数Search.apply具有签名:

def apply[L <: HList, U](implicit ev: Exists[Foo[_, U]], s: Search[L, U]): U = null

在这种情况下,编译器只会在范围内有任何隐式Foo时尝试解析s

是否可以定义这样的类型类?已经存在了吗?

尝试

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")    
}
}

测试

// 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

我想原始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
}

现在有了Exists

def apply[L <: HList, U](implicit ev: Exists[Foo[_, U]], s: Search[L, U]): U = null.asInstanceOf[U]

也有效

Search[L, Boolean] //compiles
// Search[L, Double] //does not compile

在 2.13.0 中测试

libraryDependencies ++= Seq(
scalaOrganization.value % "scala-reflect" % scalaVersion.value,
scalaOrganization.value % "scala-compiler" % scalaVersion.value
)

Exists

在2.13.10 中仍在工作。

在 Scala 3 中,有 API 可以做到这一点。

import scala.quoted.{Type, Quotes, Expr, quotes}
trait Exists[A]
object Exists {
inline given [A]: Exists[A] = ${impl[A]}
def impl[A: Type](using Quotes): Expr[Exists[A]] = {
import quotes.reflect.*
Implicits.search(TypeRepr.of[A]) match {
case _: (ImplicitSearchSuccess | AmbiguousImplicits) => '{new Exists[A]{}}
case _ => report.errorAndAbort(s"no implicit ${Type.show[A]}")
}
}
}
// no implicit Int
// summon[Exists[Int]] // doesn't compile
given Int = 1
summon[Exists[Int]] // compiles
given Int = 1
given i: Int = 2
summon[Exists[Int]] // compiles

斯卡拉 3.2.0。

在 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

在斯卡斯蒂看到它。

你的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]
}

在斯卡斯蒂看到它。

相关内容

  • 没有找到相关文章

最新更新