scala - 是否有一个类型类来检查是否存在至少一个隐式类型?

标签 scala shapeless scala-macros type-level-computation scala-compiler

我有一个特质 Foo[T, U]以及给出 L <: HList 的类型级算法和目标类型 U , 告诉我是否存在 TL这样就有一个隐含的 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
}

如果没有 Foo[T, U],我希望搜索根本不会发生。对于任何 T在所有范围内,因为那时我们已经知道该算法将无法完成。换句话说,我想要一个类型类 trait Exists[F[_]]对于哪些实例存在当且仅当至少有一个隐式 F在范围内,所以函数 Search.apply而是有签名:
def apply[L <: HList, U](implicit ev: Exists[Foo[_, U]], s: Search[L, U]): U = null

在这种情况下,编译器只会尝试解析 s如果有任何隐含的 Foo在适用范围。

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

最佳答案

尝试

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
)

关于scala - 是否有一个类型类来检查是否存在至少一个隐式类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57482298/

相关文章:

user-interface - 如何将 "bind"持久数据结构发送到 Scala 中的 GUI?

scala - 使用 Scala 宏在树中查找所有可能的序列创建

Scala 3 宏 - 在运行时保留泛型

scala - 如何在dotty宏中访问case类的参数列表

java - 在 Actor 中停止 Akka Actor

Scala 从 Try 到 Future 的隐式转换

scala - YARN : how to monitor stages progress programatically? 上的 Spark 2.3.1

scala - 在函数中使用 ADT 的参数化分支

scala - 如何使用 shapeless 连接函数参数和返回值

scala - 当将 HList 与 GADT 一起使用时,我必须使用 asInstanceOf[H] 进行转换。有没有办法避免 Actor 阵容?