gpt4 book ai didi

scala - 使用 Scala 宏在树中查找所有可能的序列创建

转载 作者:行者123 更新时间:2023-12-02 21:54:38 25 4
gpt4 key购买 nike

我想使用 Scala 宏在树中找到所有可能的序列创建。

val l = List(1, 2)
val v = Vector(1, 2)
val ab = ArrayBuffer(1, 2)
val s = Seq(1, 2)

但是以下匹配不起作用:

case Apply(TypeApply(Select(path, Name("apply")), _), args) if path.tpe <:< weakTypeOf[SeqFactory[Any]] => ...

类似地,我需要按序列上的索引查找所有访问:

val v = Vector(1, 2)
val one = v(0)

或路径上的所有“apply”方法调用,其中 path.tpe <:< ????[Seq[_]

这张支票怎么写?这无法编译:

case Apply(Select(path, Name("apply")), List(idx)) if path.tpe <:< typeOf[Seq[_]]

最佳答案

我不确定您到底尝试过什么,但乍一看,您似乎缺少至少两部分:您需要使用 Traverser要遍历树的所有后代,您需要对每个候选树进行类型检查,以确保它被脱糖到您可以知道您已经有了一个 SeqFactory 的应用程序。

例如,下面是一个快速实现,它在编译时打印类中的所有序列创建树:

import scala.language.experimental.macros
import scala.reflect.macros.Context

object SeqSearch {
def printCreatesInClass = macro printCreatesInClass_impl

def printCreatesInClass_impl(c: Context) = {
import c.universe._
import scala.collection.generic.SeqFactory

val factorySym = c.typeOf[SeqFactory[Seq]].typeSymbol

def isCreation(tree: Tree) = c.typeCheck(tree) match {
case Apply(TypeApply(Select(factory, name), _), _) if
factory.tpe.baseClasses.contains(factorySym) &&
name == newTermName("apply") => true
case _ => false
}

object printCreates extends Traverser {
override def traverse(tree: Tree) = tree match {
case application @ Apply(_, args) if isCreation(application) =>
println("Matched create: " + application)
super.traverseTrees(args)
case _ => super.traverse(tree)
}
}

printCreates(c.enclosingClass)

c.literalUnit
}
}

它的工作原理如下:

scala> class Foo {
| SeqSearch.printCreatesInClass
| val l = List(1, 2)
| val v = Vector(1, 2)
| val ab = collection.mutable.ArrayBuffer(1, 2)
| val s = Seq(1, 2)
| }
Matched create: List(1, 2)
Matched create: Vector(1, 2)
Matched create: collection.mutable.ArrayBuffer(1, 2)
Matched create: Seq(1, 2)
defined class Foo

查找访问类似 - 只需将以下方法添加到上面的对象即可:

  def printAccessesInClass = macro printAccessesInClass_impl

def printAccessesInClass_impl(c: Context) = {
import c.universe._

def isAccess(tree: Tree) = c.typeCheck(tree) match {
case Apply(Select(seq, name), _) if
seq.tpe <:< typeOf[Seq[Any]] &&
name == newTermName("apply") => true
case _ => false
}

object printAccesses extends Traverser {
override def traverse(tree: Tree) = tree match {
case application @ Apply(_, args) if isAccess(application) =>
println("Matched access: " + application)
super.traverseTrees(args)
case _ => super.traverse(tree)
}
}

printAccesses(c.enclosingClass)

c.literalUnit
}

然后:

scala> class Foo {
| SeqSearch.printCreatesInClass
| SeqSearch.printAccessesInClass
| val xs = List(1, 2, 3)
| val xh = xs(0)
| }
Matched create: List(1, 2, 3)
Matched access: xs(0)
defined class Foo

调整 Traverser 的副作用来捕获您感兴趣的任何信息应该非常容易,而不仅仅是在编译时打印树。

关于scala - 使用 Scala 宏在树中查找所有可能的序列创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17969845/

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