gpt4 book ai didi

scala - 使用 "Prolog in Scala"查找可用的类型类实例

转载 作者:行者123 更新时间:2023-12-03 06:54:42 25 4
gpt4 key购买 nike

考虑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

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

现在,我知道 Scala 隐式查找系统所属的原始约束/逻辑编程环境并不意味着用于此类技巧,并且无法“返回”多个找到的值Src 开箱即用,所以我的问题是:是否有一个“魔术”可以让它工作,以便我能以某种方式获得 X 的所有可能值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 的所有实例.

最佳答案

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

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

<小时/>

仍在 2.13.10 中工作。

Scala 3 实现类似

import dotty.tools.dotc.typer.{Implicits => dottyImplicits}
import scala.quoted.{Expr, Quotes, Type, quotes}

inline def allImplicits[A]: List[String] = ${impl[A]}

def impl[A: Type](using Quotes): Expr[List[String]] = {
import quotes.reflect.*
given c: dotty.tools.dotc.core.Contexts.Context =
quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx

val typer = c.typer

val search = new typer.ImplicitSearch(
TypeRepr.of[A].asInstanceOf[dotty.tools.dotc.core.Types.Type],
dotty.tools.dotc.ast.tpd.EmptyTree,
Position.ofMacroExpansion.asInstanceOf[dotty.tools.dotc.util.SourcePosition].span
)

def eligible(contextual: Boolean): List[dottyImplicits.Candidate] =
if contextual then
if c.gadt.isNarrowing then
dotty.tools.dotc.core.Contexts.withoutMode(dotty.tools.dotc.core.Mode.ImplicitsEnabled) {
c.implicits.uncachedEligible(search.wildProto)
}
else c.implicits.eligible(search.wildProto)
else search.implicitScope(search.wildProto).eligible


def implicits(contextual: Boolean): List[dottyImplicits.SearchResult] =
eligible(contextual).map(search.tryImplicit(_, contextual))

val contextualImplicits = implicits(true)
val nonContextualImplicits = implicits(false)
val contextualSymbols = contextualImplicits.map(_.tree.symbol)
val filteredNonContextual = nonContextualImplicits.filterNot(sr => contextualSymbols.contains(sr.tree.symbol))

val implicitStrs = (contextualImplicits ++ filteredNonContextual).collect {
case success: dottyImplicits.SearchSuccess => success.tree.asInstanceOf[ImplicitSearchSuccess].tree.show
}

Expr(implicitStrs)
}
trait CanFoo[T, U]

object CanFoo {
given canFooIntString: CanFoo[Int, String] with {}
given canFooDblString: CanFoo[Double, String] with {}
given canFooBoolString: CanFoo[Boolean, String] with {}
given canFooIntSym: CanFoo[Int, Symbol] with {}
given canFooDblSym: CanFoo[Double, Symbol] with {}
given canFooBoolSym: CanFoo[Boolean, Symbol] with {}
}

allImplicits[CanFoo[_, String]]
//"CanFoo.canFooIntString", "CanFoo.canFooBoolString", "CanFoo.canFooDblString"

Scala 3.2.0。

关于scala - 使用 "Prolog in Scala"查找可用的类型类实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26723337/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com