伟大的问题! R做了一些与其论证特有的东西,这会导致很多混淆,但也非常有用。
当您将参数传递给R函数时,直到 它才在函数内部实际使用。在此之前,参数在 附近的一个称为promise的特殊容器中。承诺持有 表达式和他们应该被评估的环境 - 对于 参数,这是调用者的环境。
但是,只要你使用函数内部的参数,它的值是 计算。这就是system.time
的工作原理。简化:
system.time = function (expr) {
before = proc.time()
expr
proc.time() - before
}
换句话说,功能简单的记录时间看其 参数之前。 然后它查看它的参数并因此引起它的评估,然后它记录经过的时间。但请记住, 参数的评估发生在调用者的范围内,因此在您的情况下, 指定的目标(df
)也在父范围内可见。
在第二个示例中,函数fx
从不查看其参数,因此它永远不会被评估。您可以轻松地改变这种状况,迫使其 参数的评价,简单地使用它:
fx <- function(z) {
z
return(1)
}
实际上,R有一个特殊的功能 - force
为了这个目的:
fx <- function(z) {
force(z)
return(1)
}
但force
是简单的语法糖,它的定义很简单,就是返回 它的参数:
force = function (x) x
事实上, R不直接评估其参数是有用的,因为 也可以检索函数内的未评估形式。这被称为 non-standard evaluation,并且它有时用于评价在不同范围(使用eval
功能与指定其 参数envir
)的 表达,或检索关于未计算的,表达 信息。
许多功能使用,最突出plot
,其中猜测基础上绘制的变量/表达式默认 轴标签:
x = seq(0, 2 * pi, length.out = 100)
plot(x, sin(x))
现在轴标签是x
和sin(x)
。该plot
函数知道这一点,因为 它里面,它可以看看它的功能参数未计算的表达式:
xlabel = deparse(substitute(x))
ylabel = deparse(substitute(y))
substitute
检索未计算的表达式。 deparse
将其转换为字符串表示形式。
好的答案,除了'system.time'实际上并没有使用'eval'(至少不是在我的R版本中)。它直接评估promise表达式,甚至不使用'force',就像在第二个版本的'fx'中一样。 – mrip 2014-12-03 12:50:43
@mrip是的,我有一半的想法来重写我的答案,因为我的简化实际上使它更复杂。在R中,*每个*函数参数都是一个承诺,非标准评估就是这样一个特殊情况,即用户不立即评估函数参数,而是替换它。 – 2014-12-03 13:01:47
@mrip从头开始,我完全重写了答案。你怎么看?现在更为正确,但它仍然可以理解吗? – 2014-12-03 13:25:34