使用“Scala 中的 Prolog"查找可用的类型类实例 [英] Using the "Prolog in Scala" to find available type class instances
问题描述
考虑到 https://speakerdeck.com/folone/theres-a-prolog-in-your-scala,我想滥用"Scala 类型系统来查找 eg 的所有实例CanBuildFrom
匹配给定条件.Prolog 风格,我将评估以下伪代码行中的某些内容:
Considering https://speakerdeck.com/folone/theres-a-prolog-in-your-scala, I would like to "abuse" the Scala type system to find all instances of e.g. CanBuildFrom
that match a given criteria. Prolog style, I would evaluate something in the lines of the following pseudocode:
can_build_from(Src, int, list[int])
Src = somecollectiontype1[int]
Src = somecollectiontype2[int]
... etc
即运行时将查找 Src
满足语句 can_build_from(Src, int, list[int])
的所有值.
i.e. the runtime would look up all the values for Src
that satisfy the statement can_build_from(Src, int, list[int])
.
现在,我知道 Scala 隐式查找系统所在的原始约束/逻辑编程环境不打算用于此类技巧,并且不能返回"多个已找到的值Src
开箱即用,所以我的问题是:是否有一个魔术技巧"可以使其工作,以便我以某种方式获得 X
的所有可能值CanBuildFrom[X, Int, List[Int]]
?
Now, I'm aware that the primitive constraint/logic programming environment, which the Scala implicit lookup system is, isn't meant to be used for such tricks and is not able to "return" more than one found value for Src
out of the box, so my question is: is there a "magic trick" to make it work so that somehow I'd get all the possible values for X
in 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]
.
now I'd like to query CanFoo[X, String]
and get back X ∈ [Int, Double, Boolean]
, or CanFoo[Int, X]
and get back X ∈ [String, Symbol]
.
或者,CanFoo[X, String]
将返回 List(canFooIntString, canFooDblString, canFooBoolString)
,即所有匹配的 CanFoo
实例.
Alternatively, CanFoo[X, String]
would return List(canFooIntString, canFooDblString, canFooBoolString)
, i.e. all instances of CanFoo
that match.
推荐答案
这可以通过编译器内部实现(至少在某些情况下)
This can be done (at least in some cases) with compiler internals
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 中测试.
Tested in 2.13.0.
这篇关于使用“Scala 中的 Prolog"查找可用的类型类实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!