我正在尝试调用函数`function`
以在R代码中定义一个函数。
我们都知道™️,`function`
是.Primitive
,当用户使用常规语法(即
mean1 = function (x, ...) base::mean(x, ...)
但是没有什么阻止我直接调用该原语的。 或者我想。我可以直接调用其他基元(甚至重新定义它们;例如,在I overrode R’s builtin `for`
疯狂的时刻)。因此,这 原则上是可能的。
但是我无法使它适用于`function`
。这是我尝试过的:
# Works
mean2 = as.function(c(formals(mean), quote(mean(x, ...))))
# Works
mean3 = eval(call('function', formals(mean), quote(mean(x, ...))))
# Error: invalid formal argument list for "function"
mean4 = `function`(formals(mean), quote(mean(x, ...)))
mean3
特别有用的事实向我表明mean4
应该有效。但事实并非如此。为什么?
我检查了R源中`function`
原语的定义。 do_function
is defined in eval.c
。而且我看到它调用了CheckFormals
,这确保了每个参数都是一个符号,并且失败了。但是为什么要对此进行检查,这意味着什么呢?
最重要的是:是否可以直接调用`function`
原语?
只需澄清一下:有很简单的解决方法(此问题列出了两个,至少有三分之一)。但我想了解这是怎么做的。
答案 0 :(得分:13)
这是因为function
是一个特殊的原语:
typeof(`function`)
#> [1] "special"
不评估参数,因此您实际上已经传递了quote(formals(mean))
而不是formals(mean)
的值。我不认为没有评估技巧可以直接调用function
的方法,只有空NULL
的空形式列表除外。
答案 1 :(得分:5)
出于完整性考虑,里奥内尔(答案)的回答暗示了一种最终呼叫`function`
的方式。不幸的是,它相当有限,因为除了NULL
之外,我们无法传递任何参数定义:
mean5 = `function`(NULL, mean(x, ...))
formals(mean5) = formals(mean)
(请注意,身体周围没有引号!)
这当然是完全不切实际的(并且formals<-
内部会调用as.function
。)
答案 2 :(得分:3)
在仔细研究了源代码之后,有一些观察结果:
实际的功能创建由mkCLOSXP()完成。 function() {}
,as.function.default()
和.Primitive("function")
(也称为`function`
)都称呼这
as.function.default()
被路由到do_asfunction()的also calls CheckFormals()。但是,它直接在上面几行中构造了这些形式。
正如您所指出的,CheckFormals()
被调用的另一个地方是do_function()
内部。但是,我认为do_function()
不会被{em> .Primitive("function")
以外的任何其他事物调用,因此这是唯一在用户输入上调用CheckFormals()
的情况。
CheckFormals()
实际上确实正确验证了pairlist
对象。
您可以通过使用CheckFormals()
运行inline::cfunction
函数的一部分来自己检查最后一点
inline::cfunction( c(x="ANY"),
'Rprintf("is list?: %d\\nTag1 OK?: %d\\nTag2 OK?: %d\\nTag3 NULL?: %d\\n",
isList(x), TYPEOF(TAG(x)) == SYMSXP, TYPEOF(TAG(CDR(x))) == SYMSXP,
CDR(CDR(x)) == R_NilValue); return R_NilValue;' )( formals(mean) )
# is list?: 1
# Tag1 OK?: 1
# Tag2 OK?: 1
# Tag3 NULL?: 1
因此,在您将formals(means)
传递到.Primitive("function")
到CheckFormals()
将其转发到do_function()
之间的某个地方,该参数失去了有效性。 (我不太了解R源,无法告诉您这是怎么发生的。)但是,由于do_function()
仅由.Primitive("function")
调用,因此在任何其他示例中都不会遇到这种情况。 / p>