This question提示以下问题:有没有办法查看调用堆栈中的special primitive函数?
例如,创建一个在退出时返回调用堆栈的函数:
myFun <- function(obj){
on.exit(print(sys.calls()))
return(obj)
}
调用此函数并使用assign
将其结果分配给对象可避免使用特殊的原始函数:
> assign("myObj",myFun(4))
[[1]]
assign("myObj", myFun(4))
[[2]]
myFun(4)
但是使用赋值运算符,它会被排除在堆栈之外
> `<-`(myObj, myFun(6))
[[1]]
myFun(6)
当然,想要在调用堆栈中看到赋值运算符可能并不常见,但rep
和log
等其他函数也会被隐藏
答案 0 :(得分:6)
我认为没有办法通过调用堆栈访问对原始函数的调用。这就是原因。
评估“典型”R函数时:
当函数调用彼此嵌套时构建的封闭环境链是“调用堆栈”或“帧堆栈”,sys.calls()
,sys.frames()
等提供了一些访问权限
我强烈怀疑对原始函数的调用没有出现在调用堆栈上,因为在评估期间没有创建R端环境。没有创建环境,因此调用堆栈上不会出现任何环境。
有关更多见解,请参阅约翰·钱伯斯如何描述Software for Data Analysis第464页对原始函数的评估:
对这些功能之一的调用的评估以通常的方式开始, 但是当评估者发现函数对象是基元时 它不是R中定义的函数,而是分支到完全不同的函数 计算。该对象似乎只是一个带有形式的函数对象 参数和函数.Primitive()的调用,带有字符串参数。 实际上,它基本上只包含一个表的索引 实现R核心的C代码。表的条目标识了一个 核心中的C例程负责评估对此特定的调用 原始。评估者将控制转移到该例程,并期望 将C语言指针返回到表示的R对象的例程 电话的价值。
答案 1 :(得分:1)
我不认为乔希的回答是正确的。
好吧,如果<-
在您的示例中的调用堆栈上, 将是正确的。 但它不是。
小概述:正常的R函数评估将参数视为 promises ,在访问时会被懒惰地评估。这意味着在以下调用中:
foo(bar(baz))
bar(baz)
在 foo
内评估(如果有的话)。因此,如果我们检查bar
内的调用堆栈,就像这样:
bar = function (x) {
sys.calls()
}
...然后它看起来如下:
[[1]]
foo(bar(baz))
[[2]]
bar(baz)
唉,正如您所指出的,<-
(和=
)不是正常函数,它是一个原始函数(BUILTINSXP
)。事实上,它是defined in the R source如下:
{"<-", do_set, 1, 100, -1, {PP_ASSIGN, PREC_LEFT, 1}},
看看第四个论点:100
。此代码之前的注释解释了数字的含义。这是相关部分,解释最左边的数字:
Z = 1表示在调用(
之前评估参数BUILTINSXP
)
这意味着在分配之前,对bar(baz)
的调用进行了以下代码评估:
`<-`(x, bar(baz))
这就是为什么<-
未显示在sys.calls()
列表中的原因:不是当前通话。它在bar
完成评估后被调用。
有一种方法可以解决此限制:您可以在R代码中重新定义<-
/ =
。如果你这样做,它的行为就像一个普通的R函数:
`<-` = function (lhs, rhs) {
name = as.name(deparse(substitute(lhs), backtick = true))
rhs # evaluate expression before passing it to `bquote`, for a cleaner call stack
eval.parent(bquote(base::`<-`(.(name), .(rhs))))
}
但是,请注意,在重新定义<-
的范围内,每个后续分配都会产生不可忽视的性能影响:实际上,它会使分配大约为1000( !!!) 慢点。这通常是不可接受的。