gpt4 book ai didi

scala - 使用宏在 thunk 前面粘贴 import 语句

转载 作者:行者123 更新时间:2023-12-02 00:05:37 25 4
gpt4 key购买 nike

this question 触发,我想知道是否可以编写一个 def-macro 来实现结果:

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

object CarImpl {
def impl(c: Context)(fun: c.Expr[Unit]): c.Expr[Unit] = {
import c.universe._
val all = "_": TermName
val imp = c.Expr(Import(c.prefix.tree, ImportSelector(all, -1, all, -1) :: Nil))
val tree = reify {
imp.splice
fun.splice
} .tree
c.Expr(tree)
}
}
class Car(var speed: Int, var color: String) {
def set(fun: Unit): Unit = macro CarImpl.impl
}

应用:

val myCar = new Car(5, "red")
myCar.set { color = "blue" }

编译失败,因为:未找到:value color。把 import 语句“粘贴”在它前面似乎还不够。如果可以实现总体想法,有什么线索吗?即下面应该是合成输出

val myCar = new Car(5, "red")

{
import myCar._
color = "blue"
}

最佳答案

获得这种语法是可能的,但它需要一种涉及结构类型的疯狂技巧(并且需要额外的一行样板文件)。我写了a blog post详细讨论了这个技巧,并将在这里给出一个简化版本。

首先是set 的宏实现(注意我使用的是quasiquotes,现在在2.10 中可以作为插件使用):

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

trait SetterBuilder {
def set_impl(c: Context)(assignments: c.Expr[Unit]): c.Expr[Unit] = {
import c.universe._

val rewriteOne: PartialFunction[Tree, Tree] = {
case q"${_}.$n($v)" => q"${c.prefix}.$n($v)"
}

val rewrite: PartialFunction[Tree, Tree] = rewriteOne orElse {
case block: Block => q"{ ..${block collect rewriteOne} }"
}

c.Expr(
rewrite.lift(assignments.tree).getOrElse(
c.abort(c.enclosingPosition, "Not a set of assignments!")
)
)
}
}

然后是结构类型的东西:

trait SyntaxBuilder {
def syntax_impl[A: c.WeakTypeTag](c: Context) = {
import c.universe._

val anon = newTypeName(c.fresh())
val declarations = c.weakTypeOf[A].declarations

val (getters, setters) = declarations.collect {
case sym: MethodSymbol if sym.isSetter => (
q"def ${sym.getter.name} = ???",
q"def ${sym.name}(x: ${sym.paramss.head.head.typeSignature}) = ???"
)
}.unzip

c.Expr[Any](q"class $anon { ..$getters; ..$setters }; new $anon {}")
}
}

现在我们将它们结合在一起并定义我们的类:

object Evil extends SyntaxBuilder with SetterBuilder {
def syntax[A] = macro syntax_impl[A]
}

case class Car(var speed: Int, var color: String) {
def set(assignments: Unit): Unit = macro Evil.set_impl
}

object Car {
val syntax = Evil.syntax[Car]
}

我们把样板文件移开:

import Car.syntax._

我们完成了:

scala> val car = new Car(0, "blue")
car: Car = Car(0,blue)

scala> car set {
| color = "red"
| speed = 10000
| }

scala> car
res0: Car = Car(10000,red)

参见 the blog post一个功能更全的版本,一个解释,并为将这个可怕的代码引入世界而道歉。

关于scala - 使用宏在 thunk 前面粘贴 import 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18537093/

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