多个参数和参数列表的准报价 [英] Quasiquotes for multiple parameters and parameter lists
问题描述
Quasiquotes 令人惊叹-它们使在Scala中编写宏的痛苦大大减轻了,而在我经验,他们几乎总是完全按照我的期望工作.最好的是,它们现在可以在Scala 2.10中作为插件使用作为插件.
这个问题是关于我在撰写此博客文章时遇到的一个小问题一个>.当我可以找到几分钟的时候,这是我要查找的东西的清单,但是我认为我会在这里张贴它,以防别人打败我,并帮助遇到相同问题的其他人. /p>
假设我有一个名称-类型对的列表列表: 我想将它们变成一棵看起来像这样的树: 以下工作正常: 也就是说,它会构建以下树: 哪个建议我应该能够写这样的东西: 或者更简单一点,在一个参数列表中包含多个参数: 都不起作用-我收到这样的错误: 足够好-我可以看到拟报价员的样子,就像我在构建类型化表达式而不是在 我知道我可以手动构建参数定义: 现在 但不是 所以这里有两个问题.首先,如何在引用的参数列表的上下文之外使用准引用将名称类型对转换为参数 对于整个该死的事情,很容易退回到手动AST构造(请参阅我的帖子),但是我希望能够使用准引用. 以下是您解决问题的快速方法: 如您所见,特殊的... $ splice允许您定义具有多个参数列表的函数.函数参数本身的表示方式与常规val相同. 另一个可能在其中使用... $的示例: Quasiquotes are amazing—they make writing macros in Scala hugely less painful, and in my experience they almost always just work exactly as I'd expect. And best of all, they're now available as a plugin in Scala 2.10. This question is about a small problem that I ran into while writing this blog post. It's on my list of stuff to look into when I can find a few minutes, but I figured I'd post it here in case someone else can beat me to it, and to help other people who are running into the same question. Suppose I have a list of lists of name-type pairs: I want to turn these into a tree that looks like this: The following works just fine: That is, it builds the following tree: Which suggests that I should be able to write something like this: Or a little more simply, with multiple parameters in a single parameter list: Neither works—I get errors like this: Fair enough—I can see how it would look to the quasiquoter like I'm building typed expressions rather than defining parameters in I know that I can build the parameter definitions manually: And now the But not the So there are two questions here. First, how can I use quasiquotes to turn a name-type pair into a parameter It's easy enough to fall back to manual AST construction for the whole damn thing (see my post for an example), but I'd like to be able to use quasiquotes instead. Here is the quick solution to your problem: As you can see special ...$splice lets you define a function with multiple argument lists. Function arguments themselves are represented in the same manner as regular vals. Another example where ...$it might be useful:
这篇关于多个参数和参数列表的准报价的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!val pss = List(
List(newTermName("x") -> typeOf[Int], newTermName("y") -> typeOf[Char]),
List(newTermName("z") -> typeOf[String])
)
def foo(x: Int, y: Char)(z: String) = ???
q"def bar(${pss.head.head._1}: ${pss.head.head._2}) = ???"
def bar(x: Int) = ???
val quoted = pss.map(_.map { case (n, t) => q"$n: $t" })
q"def foo..${quoted.map(ps => q"($ps)")} = 1"
q"def baz(..${quoted.head}) = ???"
<console>:28: error: type mismatch;
found : List[c.universe.Typed]
required: List[c.universe.ValDef]
q"def baz(..${quoted.head}) = ???"
^
quoted
中定义参数一样.我想尝试尝试的所有显而易见的事情都没有奏效(添加= _
,将准引用显式键入为ValDef
等).val valDefs = pss.map(
_.map {
case (n, t) => ValDef(Modifiers(Flag.PARAM), n, TypeTree(t), EmptyTree)
}
)
baz
版本(带有一个参数列表)可以工作:q"def baz(..${valDefs.head}) = ???"
foo
版本(具有多个参数列表的版本).ValDef
?其次,如何将参数定义列表列表转换为多个参数列表?val pss = List(
List(newTermName("x") -> typeOf[Int], newTermName("y") -> typeOf[Char]),
List(newTermName("z") -> typeOf[String])
)
val vparamss: List[List[ValDef]] = pss.map { _.map { case (name, tpe) => q"val $name: $tpe" } }
q"def foo(...$vparamss)"
val xy = List(List(q"x"), List(q"y"))
q"f(...$xy)" // same as q"f(x)(y)"
val pss = List(
List(newTermName("x") -> typeOf[Int], newTermName("y") -> typeOf[Char]),
List(newTermName("z") -> typeOf[String])
)
def foo(x: Int, y: Char)(z: String) = ???
q"def bar(${pss.head.head._1}: ${pss.head.head._2}) = ???"
def bar(x: Int) = ???
val quoted = pss.map(_.map { case (n, t) => q"$n: $t" })
q"def foo..${quoted.map(ps => q"($ps)")} = 1"
q"def baz(..${quoted.head}) = ???"
<console>:28: error: type mismatch;
found : List[c.universe.Typed]
required: List[c.universe.ValDef]
q"def baz(..${quoted.head}) = ???"
^
quoted
. None of the obvious things I could think to try worked (adding = _
, explicitly typing the quasiquote as a ValDef
, etc.).val valDefs = pss.map(
_.map {
case (n, t) => ValDef(Modifiers(Flag.PARAM), n, TypeTree(t), EmptyTree)
}
)
baz
version (with one parameter list) works:q"def baz(..${valDefs.head}) = ???"
foo
version (the one with multiple parameter lists).ValDef
outside of the context of a quoted parameter list? And second, how can I turn a list of lists of parameter definitions into multiple parameter lists?val pss = List(
List(newTermName("x") -> typeOf[Int], newTermName("y") -> typeOf[Char]),
List(newTermName("z") -> typeOf[String])
)
val vparamss: List[List[ValDef]] = pss.map { _.map { case (name, tpe) => q"val $name: $tpe" } }
q"def foo(...$vparamss)"
val xy = List(List(q"x"), List(q"y"))
q"f(...$xy)" // same as q"f(x)(y)"