Scala AST Select vs Apply

时间:2013-11-30 19:45:17

标签: scala abstract-syntax-tree scala-macros

当选择合适时和申请时,我很困惑。我认为apply是一个函数或方法应用程序,因此

scala> val expr = u reify { Random.nextInt }
expr: reflect.runtime.universe.Expr[Int] = Expr[Int](Random.nextInt())

scala> u showRaw expr.tree
res0: String = Apply(Select(Ident(scala.util.Random), newTermName("nextInt")), List())

是我的期望;带有空参数列表的nextInt应用程序。

此外,

scala> val expr = u reify { Random.shuffle(List("sammy", "snake")) }
expr: reflect.runtime.universe.Expr[List[String]] = Expr[List[String]](Random.shuffle(List.apply("sammy", "snake"))(List.canBuildFrom))

scala> u showRaw expr.tree
res2: String = Apply(Apply(Select(Ident(scala.util.Random), newTermName("shuffle")), List(Apply(Select(Ident(scala.collection.immutable.List), newTermName("apply")), List(Literal(Constant("sammy")), Literal(Constant("snake")))))), List(Select(Ident(scala.collection.immutable.List), newTermName("canBuildFrom"))))

再次是我所期望的 - 一个shuffle方法的应用,带有一个字符串列表。

然而,

scala> val expr = u reify { Random.shuffle(List("sammy", "snake")).head }
expr: reflect.runtime.universe.Expr[String] = Expr[String](Random.shuffle(List.apply("sammy", "snake"))(List.canBuildFrom).head)

scala> u showRaw expr.tree
res1: String = Select(Apply(Apply(Select(Ident(scala.util.Random), newTermName("shuffle")), List(Apply(Select(Ident(scala.collection.immutable.List), newTermName("apply")), List(Literal(Constant("sammy")), Literal(Constant("snake")))))), List(Select(Ident(scala.collection.immutable.List), newTermName("canBuildFrom")))), newTermName("head"))

是头上的选择。我很困惑,因为我会认为那个外部节点将是头部的应用程序。当head是一种方法时,为什么选择它?

是否有一个网页详细说明了选择和应用之间的区别,因为我找不到。

2 个答案:

答案 0 :(得分:4)

SelectApply的含义纯粹是语法上的。

Select(prefix, newTermName("member"))表示prefix.member

Apply(prefix, List(arg1, arg2, ...))表示prefix(arg1, arg2, ...)

技术上,Random.nextIntSelect,但Scala类型检查器将其包含在另外的Apply中,因为Random.nextInt被定义为一个带有单个空参数的函数名单。换句话说,这是一个由类型搜索者执行的贬低。

List的{​​{1}}方法不是这种情况。如果你看一下它的定义,它需要 no 参数列表:

head

这就是为什么类型检查器不会将它包装在def head: A 树中。

总结 - 采用单个空参数列表的方法与不采用参数列表的方法之间存在差异。作为一个语法糖,Scala允许使用单个空参数列表调用方法,就好像它们没有参数列表(没有任何parens),但是在这种情况下,类型检查器仍会添加Apply

答案 1 :(得分:1)

在这种情况下,树精确地再现了Scala程序的语法结构。 Select对应于成员选择,例如到foo.bar,而Apply代表参数列表的应用,例如baz(1, 2, 3)

如果我们在Scala中有一个空的arglist方法,例如def x() = ???(或Random.nextInt()),然后可以将其调用写为Select(对应something.x)和Apply(Select(...), Nil)(对应{{1} }),因为两者都是有效的Scala表达式。

如果我们在Scala中使用了一个nullary方法,例如something.x()(或def y = ???),则其调用只能写为List.head(对应Select)。如果我们写somethingElse.y,那就意味着Apply(Select(...), Nil),这意味着将空参数列表应用于somethingElse.y()上调用方法y的结果。