使用“Scala 中的 Prolog"查找可用的类型类实例 [英] Using the "Prolog in Scala" to find available type class instances

查看:48
本文介绍了使用“Scala 中的 Prolog"查找可用的类型类实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑到 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆