从一个更大的例子中提取的下面的宏应该创建一个只有对以下内容的引用的树this:
def echoThisImpl(c:Context): c.Expr[Any] = {
import c.universe._
val selfTree = This(c.enclosingClass.symbol)
c.Expr[AnyRef](selfTree)
}
def echoThis: Any = macro CallMacro.echoThisImpl
Run Code Online (Sandbox Code Playgroud)
然而,对于一个呼叫echoThis如
object Testing extends App {
val thisValue = CallMacro.echoThis
println(thisValue)
}
Run Code Online (Sandbox Code Playgroud)
无法使用消息进行编译
[error] /home/rafael/dev/scala/goose/goose-macros/src/test/scala/Testing.scala:8: type mismatch;
[error] found : <noprefix>
[error] required: Any
[error] val thisValue = CallMacro.echoThis
Run Code Online (Sandbox Code Playgroud)
如果我设置-Ymacro-debug-lite标志,则生成的树是This(newTermName("<local Testing>")).
假设我有这个宏:
import language.experimental.macros
import scala.reflect.macros.Context
object FooExample {
def foo[A](xs: A*): Int = macro foo_impl[A]
def foo_impl[A](c: Context)(xs: c.Expr[A]*) = c.literal(xs.size)
}
Run Code Online (Sandbox Code Playgroud)
这与"真正的"varargs一样有效:
scala> FooExample.foo(1, 2, 3)
res0: Int = 3
Run Code Online (Sandbox Code Playgroud)
但是归因于varargs类型的序列的行为让我感到困惑(在Scala 2.10.0-RC3中):
scala> FooExample.foo(List(1, 2, 3): _*)
res1: Int = 1
Run Code Online (Sandbox Code Playgroud)
并且表明推断类型没有任何可疑的事情:
scala> FooExample.foo[Int](List(1, 2, 3): _*)
res2: Int = 1
Run Code Online (Sandbox Code Playgroud)
我原本期望编译时错误,这就是我想要的.我在我编写的大多数宏中使用了以下方法:
object BarExample {
def bar(xs: Int*): Int = macro bar_impl
def bar_impl(c: Context)(xs: c.Expr[Int]*) = {
import c.universe._
c.literal(
xs.map(_.tree).headOption map {
case Literal(Constant(x: Int)) => x …Run Code Online (Sandbox Code Playgroud) 让我思考的是为什么以下
<something> match { ... }
Run Code Online (Sandbox Code Playgroud)
无法改写为
<something>.match({ ... }) # error: identifier expected but 'match' found.
Run Code Online (Sandbox Code Playgroud)
我想这是因为它不可能match作为常规方法实现,但我不确定.或许这是出于性能原因.
此外,现在宏可用,match可以使用宏来实现吗?(不是说它应该完成,而只是假设)
编辑:这似乎与scala的实验虚拟模式匹配器有什么关系?; 感谢@ om-nom-nom指出.
鉴于知道算术final val表达式是否会被编译为编译时常量是多么困难,以及意外破坏编译时间是多么容易 ......
在编译时,有没有人能想到一种简单的方法来验证编译器是否实际上从一个复杂的算术表达式创建了一个编译时常量?我猜这可能是某种注释或宏,但也许有一些更简单的东西.例如,可能是这样的:
@CompileTime final val HALF_INFINITY = Int.MaxValue / 2
Run Code Online (Sandbox Code Playgroud)
是可能的.
我是scala宏的新手,我花了几天时间试着写第一篇.我有quasiquotes连接问题.
有一个案例条款列表,让我们说如下:
val cases = cq"x => 1 " :: cq"_ => 0 " :: Nil
Run Code Online (Sandbox Code Playgroud)
我需要从中构建一个部分功能.问题是我不知道如何将它们粘贴到最终的quasiquote中.文档说我应该做这样的事情:
q"{ case ..$cases }"
Run Code Online (Sandbox Code Playgroud)
但如果我这样做,它就不起作用.
有没有办法从这样的列表构建PartialFunction?
谢谢你的帮助.
我正在尝试编写一个宏,它接受一个带有java bean接口和case类的类,并创建一对用于在它们之间进行映射的方法.
我试图检查每个属性的类型是否匹配,但java bean中的类型是例如java.lang.Long,case类中的类型是scala.Long.
我的问题是,给定这些2的c.universe.Type对象,有没有办法测试它们之间是否存在隐式转换?即测试我是否可以将一个传递给一个期望另一个的方法.
所以我在函数上有一个注释(DefDef).此注释具有参数.但是,我对如何从构造函数中获取参数感到困惑.
用法示例:
class TestMacro {
@Foo(true)
def foo(): String = ""
foo
}
Run Code Online (Sandbox Code Playgroud)
这是注释的代码:
class Foo(b: Boolean) extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro Foo.impl
}
object Foo {
def impl(c: whitebox.Context)(annottees: c.Tree*): c.Expr[Any] = {
import c.universe._
//how do I get value of `b` here???
c.abort(c.enclosingPosition, "message")
}
}
Run Code Online (Sandbox Code Playgroud) 考虑以下注释:
// ok to have more meta
@field
@param
@compileTimeOnly("Only for code generation")
case class Annot(value: String) extends ConstantAnnotation
Run Code Online (Sandbox Code Playgroud)
现在三种用途:
case class A(x: Int, @Annot("z") y: String)
object A:
def f1(x: Int, y: String @Annot("z")): A = ???
def f2(x: Int, @Annot("z") y: String): A = ???
Run Code Online (Sandbox Code Playgroud)
我想使用 Scala 3 宏来查找每个注释。
Symbol.caseFields为我提供参数列表,并且在每个参数(类型为Symbol)上,方法annotations为我提供了我正在寻找的内容。ValDef. 如果param.tpt.tpe匹配,AnnotatedType(tpe, t)那么t就是我正在寻找的注释。知道如何获取为方法中的参数提供的注释吗?当我打印术语/符号/树/...时,在这种情况下我什至看不到“z”。
我想用宏转换Scala XML文字.(不是带XML的字符串文字,而是实际的XML文字).据我所知,XML文字实际上并没有构建在AST级别的语言中,而是在解析器中被贬低.有趣的是,这确实有效:
case q"<specificTag></specificTag>" => ... // succeeds for specificTag with no
// attributes and children
Run Code Online (Sandbox Code Playgroud)
但显然,这完全没用,因为不可能以任意方式匹配任意xml.就像是
case q"<$prefix:$label ..$attrs>$children</$prefix:$label>" => ...
Run Code Online (Sandbox Code Playgroud)
无法工作,因为我们必须在模式中绑定相同的变量两次.
打印出这样的xml文字表达式的树实际上给出了desugared版本.例如.
new _root_.scala.xml.Elem(null,"specificTag",_root_.scala.xml.Null,$scope,false)
Run Code Online (Sandbox Code Playgroud)
但尝试匹配此失败:
case q"new _root_.scala.xml.Elem(..$params)" => ... // never succeeds
Run Code Online (Sandbox Code Playgroud)
我很迷惑!我的问题是:有没有办法可靠地匹配scala宏中的任意xml litarals?另外:为什么它们在quasiquotes中支持常量xml而不是desugared值呢?
这个问题是在 Scala 3/Dotty 中提出的,但应该推广到 MetaML 系列之外的任何语言。
\nScala 3 宏教程:
\nhttps://docs.scala-lang.org/scala3/reference/metaprogramming/macros.html
\n从阶段一致性原则开始,它明确指出在编译阶段定义的自由变量不能被下一阶段使用,因为它的绑定对象不能持久化到不同的编译器进程:
\n\n\n...因此,程序的结果将需要将程序状态本身作为其部分之一进行持久化。我们不想\xe2\x80\x99 这样做,因此这种情况应该被定为非法
\n
这应该被认为是一个已解决的问题,因为许多分布式计算框架需要类似的能力来跨多台计算机持久保存对象,最常见的解决方案(如在 Apache Spark 中观察到的)使用标准序列化/pickling 来创建绑定对象的快照( Java 标准序列化,twitter Kryo/Chill)可以保存在磁盘/堆外内存上或通过网络发送。
\n教程本身也两次提出了这种可能性:
\n\n\n一个区别是 MetaML 没有 PCP 的等效项 - MetaML 中引用的代码可以访问其直接封闭环境中的变量,但有一些限制和警告,因为此类访问涉及序列化。然而,这并不构成表现力的根本增益。
\n
\n\n最后,
\nToExpr非常类似于序列化框架
相反,Scala 2 和 Scala 3(以及它们各自的生态系统)在很大程度上忽略了这些开箱即用的解决方案,只为原始类型提供默认方法(Liftable在 scala2 中,ToExpr在 scala3 中)。此外,使用宏的现有库在很大程度上依赖于手动定义准引号/引号来完成这项琐碎的任务,从而使源代码变得更长且更难以维护,同时并没有使任何东西变得更快(因为 JVM 对象序列化是高度优化的语言组件)
造成这种现状的原因是什么?我们如何改进它?
\nscala ×10
scala-macros ×10
macros ×2
scala-2.10 ×2
scala-3 ×2
annotations ×1
multistage ×1
scala-xml ×1