Scala Quasiquote Lifting

4
Scala的Quasiquotes文档在解释Lifting时提到了这一点:(链接) 引用如下:

可以同时使用lifting和反引号拼接:

 scala> val ints = List(1, 2, 3)
 scala> val f123 = q"f(..$ints)"
 f123: universe.Tree = f(1, 2, 3)

 scala> val intss = List(List(1, 2, 3), List(4, 5), List(6))
 scala> val f123456 = q"f(...$intss)"
 f123456: universe.Tree = f(1, 2, 3)(4, 5)(6)

在代码示例中,具体是在哪里实现了提升(lifting)和取消引用拼接(unquote splicing)?

1个回答

5

这两个例子中都同时发生了。

解引用是将一个 Tree 替换到另一个 Tree 结构中的过程(类似于插值)。在这个例子中,ints 并不是一个完整的 Tree,但是存在一个 Liftable[List[T]],使我们可以将一个 List[T] 解引用为一个 Tree,就像它是一个 Tree 一样(即 Liftable 告诉编译器如何将这里的字面量 List[Int] 转换成一个 Tree,以便可以进行替换)。

引用文档:

解引用 splicing 是一种解引用可变数量元素的方法。

这里,可变数量元素是我们想要解引用的 List 中的元素。如果我们执行 q"f($ints)",那么我们只会将 ints 解引用为 f 的单个参数。但也许我们想要将重复的参数应用于 f。为此,我们使用 解引用 splicing

q"f(..$ints) // Using `..` means we get f(1, 2, 3) instead of f(List(1, 2, 3))

再次强调,文档可以最好地解释:

在未引用的圆点附近注释表示压平程度,也称为拼接等级。 .. $ 期望参数为 Iterable [Tree],而 ... $ 则期望 Iterable [Iterable [Tree]]

因此,提升允许我们将List [T]引用到树f(x)中,就像它是Iterable [Tree] 一样,而未引用拼接允许我们将List [T]包含的可变数量的元素作为f的多个参数进行解引用。


下面是不同相关组合:

val listTree = q"scala.collection.immutable.List(1, 2, 3)"
val treeList = List(q"1", q"2", q"3")
val literalList = List(1, 2, 3)

scala> q"f($listTree)" // plain unquoting from another Tree
res6: reflect.runtime.universe.Tree = f(scala.collection.immutable.List(1, 2, 3))

scala> q"f($literalList)" // unquoting from lifting
res7: reflect.runtime.universe.Tree = f(scala.collection.immutable.List(1, 2, 3))

scala> q"f(..$treeList)" // plain unquote splicing
res8: reflect.runtime.universe.Tree = f(1, 2, 3)

scala> q"f(..$literalList)" // unquote splicing and lifting
res9: reflect.runtime.universe.Tree = f(1, 2, 3)

谢谢,但我只想说给一个表面上是替换机制的东西加上前缀un-是多么愚蠢。 - RoyalCanadianKiltedYaksman
这并不是真的愚蠢。符号被解析为它们所指代的内容,如果 val x = 5,那么后面的 x 就是 5。引用会给出一个符号,'x 是符号 x 本身。稍后你可以取消引用 'x 并将其放入代码中,在那里它将引用该上下文中的某些内容。 - muhuk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接