使用“Scala中的Prolog”查找可用的类型类实例

时间:2014-11-03 21:16:04

标签: scala shapeless constraint-programming logic-programming type-level-computation

考虑https://speakerdeck.com/folone/theres-a-prolog-in-your-scala,我想"滥用" Scala类型系统,用于查找例如符合给定条件的CanBuildFrom。 Prolog风格,我会评估以下伪代码的行:

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

即。运行时将查找满足语句Src的{​​{1}}的所有值。

现在,我意识到Scala隐式查找系统所处的原始约束/逻辑编程环境并不意味着用于此类技巧,并且不能"返回& #34;开箱即用can_build_from(Src, int, list[int])的价值不止一个,所以我的问题是:是否有一个"魔术技巧"使它工作,以便我以某种方式获得SrcX的所有可能值?

其他示例:

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)的所有实例。

1 个答案:

答案 0 :(得分:1)

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

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中进行了测试。