【发布时间】:2013-12-18 18:33:33
【问题描述】:
我在玩 Scala 2.11 的新宏功能。我想看看我是否可以进行以下重写:
forRange(0 to 10) { i => println(i) }
// into
val iter = (0 to 10).iterator
while (iter.hasNext) {
val i = iter.next
println(i)
}
我想我已经很接近这个宏了:
def _forRange[A](c: BlackboxContext)(range: c.Expr[Range])(func: c.Expr[Int => A]): c.Expr[Unit] = {
import c.universe._
val tree = func.tree match {
case q"($i: $t) => $body" => q"""
val iter = ${range}.iterator
while (iter.hasNext) {
val $i = iter.next
$body
}
"""
case _ => q""
}
c.Expr(tree)
}
当以forRange(0 to 10) { i => println(i) } 调用时,这会产生以下输出(至少,这是show 函数在结果树上给我的):
{
val iter = scala.this.Predef.intWrapper(0).to(10).iterator;
while$1(){
if (iter.hasNext)
{
{
val i = iter.next;
scala.this.Predef.println(i)
};
while$1()
}
else
()
}
}
看起来应该可以工作,但是我的手动定义val i和i引用之间存在冲突拼接的功能体。我收到以下错误:
ReplGlobal.abort:$line38.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw 中不存在符号值 i。 错误:符号值 i 不存在 scala.reflect.internal.FatalError:$line38 中不存在符号值 i。$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw。
然后是相当大的堆栈跟踪,导致“Abandoned crashed session”通知。
我不知道这是否是我的逻辑问题(您根本无法在引用封闭变量的函数体中拼接),或者它是否是新实现的错误。错误报告当然可以更好。我在 Repl 上运行它可能会加剧这种情况。
是否可以拆分一个函数,将主体与封闭项分开,然后重写它以便将逻辑直接拼接到结果树中?
【问题讨论】:
-
@KChalous 既然
resetAllAttrs已从 Scala 2.11 中删除,您是否曾经设法解决此问题?我有完全同样的问题,我迫切希望解决它! -
@AndrewBate 根据在线文档,
resetLocalAttrs仍然存在,应该涵盖大多数情况。不知道这是不是其中之一,但值得一试。参考:docs.scala-lang.org/overviews/macros/changelog211.html -
@AndrewBate 并根据 github 上的 scalamacros 项目,
resetLocalAttrs已重命名为untypecheck。参考:github.com/scalamacros/resetallattrs -
@KChalous 我已经调查了更多,在这个 exact 示例中,我认为
untypecheck就足够了。但是,当我尝试匹配模式q"for ($i <- $collection) $body"时,我需要旧的resetAllAttrs(或者看起来如此)。我已经为 Scala 2.11 宏使用了 resetAllAttrs 库,它可以工作,而单独的untypecheck不能,但是我很快遇到了resetAllAttrs破坏父树的常见问题。 -
@AndrewBate 不幸的是,我绝对不是这方面的专家。看起来,通过该 github 链接,您可以返回
resetAllAttrs,但由于您提到的树损坏问题,他们专门删除了它。不过,如果您需要它,请查看github.com/scalamacros/resetallattrs
标签: scala macros expression scala-macros scala-quasiquotes