如何调用“功能”功能?

时间:2019-02-08 16:39:41

标签: r

我正在尝试调用函数`function`以在R代码中定义一个函数。

我们都知道™️,`function`.Primitive,当用户使用常规语法(即

)时,R会在内部使用{em> 来定义函数。
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`原语?


只需澄清一下:有很简单的解决方法(此问题列出了两个,至少有三分之一)。但我想了解这是怎么做的。

3 个答案:

答案 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)

在仔细研究了源代码之后,有一些观察结果:

  1. 实际的功能创建由mkCLOSXP()完成。 function() {}as.function.default().Primitive("function")(也称为`function`)都称呼这

  2. as.function.default()被路由到do_asfunction()also calls CheckFormals()。但是,它直接在上面几行中构造了这些形式。

  3. 正如您所指出的,CheckFormals()被调用的另一个地方是do_function()内部。但是,我认为do_function()不会被{em> .Primitive("function")以外的任何其他事物调用,因此这是唯一在用户输入上调用CheckFormals()的情况。

  4. 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>