繁体   English   中英

R中函数调用的优先级

[英]Precedence of a function call in R

运算符优先级的标准R帮助页面上,它们不包括函数调用,在我看来这似乎相当草率。 这导致了一些问题,所以我决定只使用substitute反复试验,发现优先级似乎介于[[^

> substitute(a^b())[[1]]
`^`
> substitute(a[b]())[[1]]
a[b]

在中缀表示法中,这些将是(^ a (b ()))(([ ab) ()) (将调用运算符表示为() )。 在简单的英语中,第一个例子表明在参数ab()上调用指数函数,而在第二个例子中,最终结果是对函数a[b]的调用。

这种优先权在每种情况下都适用吗? 看起来奇怪的是,函数调用的优先级不会是常量,但如果它确实是常量的话,它就不会包含在上面的帮助页面中。

函数调用的优先级不变的

R非常像lisp,引擎盖下。

它有lisp 这样的SEXP ; SEXP是一个元组(列表),其中元组的第一个元素( [[1]] )是运算符,其余元素(通常是其他SEXP)是运算符的参数。

当你写作

paste("a",1 + 2)

R明白了

(`paste`,"a",(`+`, 1, 2))

当您运行替换时,您将获得SEXP(尽管它们像R代码一样打印),并且(最外层)SEXP的第一个元素是将在表达式中应用的最后一个运算符 - 即最低优先级。

您可能知道,您可以使用以下内容查看表达式的各个部分:

> str(as.list(quote(a^b())))
List of 3
 $ : symbol ^
 $ : symbol a
 $ : language b()

要将此理解应用于示例中的优先级。

a^b()的最后一个运算符是什么?

让我们逐步考虑它

  1. 替代并评估a
  2. 替代和评估b
  3. 评估(步骤的结果) 2没有参数(这被称为呼叫)
  4. 替代并评估^
  5. 用参数13评估4

所以最后一个运算符是名为^的值

接下来, a[b]()的最后一个运算符是什么?

  1. 替代并评估a
  2. 替代和评估b
  3. 替代和评估[
  4. 评估(步骤的结果) 3带参数(步骤的结果) 1和(步骤的结果) 2
  5. 评估(步骤的结果) 4

在这种情况下(步骤的结果) 4具有方便的名称a[b]

因此,最后一个运算符是对a[b]的调用(没有参数的评估)。


编辑:警告

我简化了这里的实际情况,因为由于R的特殊性,函数参数作为未评估(环境,表达式)对传递给函数(运算符),而不是通过引用或通过值传递,而'commit'订单与上述大致相同,实际的发货订单实际上是相反的 - 甚至是错过了步骤。 但是,您还不必担心。

也许不是“优先”问题,而是解析问题。 (但是在考虑它确实看起来像是优先级之后,需要完成“[”和“]”之间所有参数的参数匹配。)在第一个实例中,解析树构造为:

            `^`
            /  \
           a    b

> substitute(a^b())[1]
`^`()
> substitute(a^b())[[1]]
`^`
> substitute(a^b())[[2]]
a
> substitute(a^b())[[3]]
b()

在第二种情况下,它被构造为

             a[b]
            /
           NULL

但第一个元素也有一个结构:

            `[`
            / \
           a   b

> substitute(a[b]())[[1]][[1]]
`[`
> substitute(a[b]())[[1]][[2]]
a
> substitute(a[b]())[[1]][[3]]
b

我认为可能会出现歧义,因为两个函数( ^[ )只有后者实际上可以传递一个函数,因此需要先处理它。 评估a^b的结果永远不会是一个函数,所以处理为^ (a,b())是有意义的

当实际上让这样的东西真正发挥作用时,我不认为第二个是非常有用的。 为了从工作空间中获取和替换,您需要额外的提取步骤:

b <- list(mean)
> eval( substitute(a^b(1:10) , list(a=2) ))
Error in eval(expr, envir, enclos) : could not find function "b"
> eval( substitute(a^b[[1]](1:10) , list(a=2) ))
[1] 45.25483

按照@ hadley的建议,我从pryr复制了他的ast函数,它是github的pryr存储库中 draw_tree.r模块中的伴随函数call_tree 我需要这样做,因为我在路上,我的笔记本电脑仍然停留在一个没有二进制pryr的过时的R版本。 还需要安装并加载pkg:stringr以获取str_c

有了它,我们可以看到差异:

ast(a[b]())
\- ()
 \- ()
  \- `[
  \- `a
  \- `b 
ast(a^b())
\- ()
 \- `^
 \- `a
 \- ()
  \- `b 

漂亮的@hadley。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM