42

考虑到https://speakerdeck.com/folone/theres-a-prolog-in-your-scala,我想“滥用”Scala 类型系统来查找所有CanBuildFrom符合给定条件的 eg 实例。Prolog 风格,我将评估以下伪代码行中的内容:

can_build_from(Src, int, list[int])
Src = somecollectiontype1[int]
Src = somecollectiontype2[int]
... etc

即运行时将查找Src满足语句的所有值can_build_from(Src, int, list[int])

现在,我知道 Scala 隐式查找系统所在的原始约束/逻辑编程环境并不打算用于此类技巧,并且不能“返回”超过一个找到Src的值盒子,所以我的问题是:是否有一个“魔术”让它工作,以便我以某种方式获得Xin的所有可能值CanBuildFrom[X, Int, List[Int]]

附加示例:

trait CanFoo[T, U]

implicit val canFooIntString  = new CanFoo[Int,     String] {}
implicit val canFooDblString  = new CanFoo[Double,  String] {}
implicit val canFooBoolString = new CanFoo[Boolean, String] {}
implicit val canFooIntSym     = new CanFoo[Int,     Symbol] {}
implicit val canFooDblSym     = new CanFoo[Double,  Symbol] {}
implicit val canFooBoolSym    = new CanFoo[Boolean, Symbol] {}

现在我想查询CanFoo[X, String]并返回X ∈ [Int, Double, Boolean],或者CanFoo[Int, X]返回X ∈ [String, Symbol]

或者,CanFoo[X, String]将返回List(canFooIntString, canFooDblString, canFooBoolString),即CanFoo该匹配的所有实例。

4

1 回答 1

2

这可以通过编译器内部来完成(至少在某些情况下)

import scala.language.experimental.macros
import scala.reflect.internal.util
import scala.reflect.macros.{blackbox, contexts}

object Macros {

  def allImplicits[A]: List[String] = 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 search = new analyzer.ImplicitSearch(
      tree = EmptyTree.asInstanceOf[global.Tree],
      pt = tpA.asInstanceOf[global.Type],
      isView = false,
      context0 = callsiteContext.makeImplicit(reportAmbiguousErrors = false),
      pos0 = c.enclosingPosition.asInstanceOf[util.Position]
    )

    q"${search.allImplicits.map(_.tree.symbol.toString).distinct}"
  }
}

allImplicits[CanFoo[_, String]]
// List(value canFooBoolString, value canFooDblString, value canFooIntString)

在 2.13.0 中测试。

于 2019-09-19T20:56:23.507 回答