Rya*_*ell 5 expression r metaprogramming function
我正在尝试查找在任意合法 R 表达式中使用的所有函数的名称,但我找不到将以下示例标记为函数而不是名称的函数。
test <- expression(
this_is_a_function <- function(var1, var2){
this_is_a_function(var1-1, var2)
})
all.vars(test, functions = FALSE)
[1] "this_is_a_function" "var1" "var2"
Run Code Online (Sandbox Code Playgroud)
all.vars(expr, functions = FALSE) 似乎在表达式中返回函数声明 (f <- function(){}),同时过滤掉函数调用 ('+'(1,2), ...)。
是否有任何函数 - 在核心库或其他地方 - 会将“this_is_a_function”标记为函数,而不是名称?它需要处理语法上合法但可能无法正确评估的任意表达式(例如'+'(1,'duck'))
我发现了类似的问题,但它们似乎不包含解决方案。
如果需要澄清,请在下面发表评论。我正在使用解析器包来解析表达式。
我有包含整个脚本的表达式,这些脚本通常由一个包含嵌套函数定义的 main 函数组成,并在脚本末尾调用 main 函数。
函数都在表达式中定义,我不介意是否必须包含 '<-' 和 '{',因为我可以自己轻松地将它们过滤掉。
动机是获取我所有的 R 脚本并收集有关我对函数的使用如何随时间变化的基本统计数据。
基于正则表达式的方法获取函数定义,结合 James 注释中的方法获取函数调用。通常有效,因为我从不使用右手赋值。
function_usage <- function(code_string){
# takes a script, extracts function definitions
require(stringr)
code_string <- str_replace(code_string, 'expression\\(', '')
equal_assign <- '.+[ \n]+<-[ \n]+function'
arrow_assign <- '.+[ \n]+=[ \n]+function'
function_names <- sapply(
strsplit(
str_match(code_string, equal_assign), split = '[ \n]+<-'),
function(x) x[1])
function_names <- c(function_names, sapply(
strsplit(
str_match(code_string, arrow_assign), split = '[ \n]+='),
function(x) x[1]))
return(table(function_names))
}
Run Code Online (Sandbox Code Playgroud)
简短的回答: is.function
检查变量是否实际上包含函数。这不适用于(未评估的)调用,因为它们是调用。您还需要注意屏蔽:
mean <- mean (x)
Run Code Online (Sandbox Code Playgroud)
更长的答案:
恕我直言,两次出现之间存在很大差异this_is_a_function
。
在第一种情况下,this_is_a_function
一旦计算表达式,您将向具有 name 的变量分配一个函数。2+2
其差异与和之间的差异相同4
。
然而,仅仅查找并<- function ()
不能保证结果是一个函数:
f <- function (x) {x + 1} (2)
Run Code Online (Sandbox Code Playgroud)
第二次出现在语法上是函数调用。您可以从表达式中确定保存this_is_a_function
函数的调用变量需要存在才能正确计算调用。但是:仅凭该声明您不知道它是否存在。但是,您可以检查这样的变量是否存在,以及它是否是一个函数。
事实上,函数也像其他类型的数据一样存储在变量中,这意味着在第一种情况下,您可以知道 的结果function ()
将是函数,并由此得出结论,在计算该表达式之后,具有名称的变量this_is_a_function
将立即保存一个函数。
然而,R 充满了名称和函数:“->”是赋值函数的名称(保存赋值函数的变量)...
计算表达式后,您可以通过 来验证这一点is.function (this_is_a_function)
。然而,这绝不是唯一返回函数的表达式:想想
f <- function () {g <- function (){}}
> body (f)[[2]][[3]]
function() {
}
> class (body (f)[[2]][[3]])
[1] "call"
> class (eval (body (f)[[2]][[3]]))
[1] "function"
Run Code Online (Sandbox Code Playgroud)
all.vars(expr,functions = FALSE) 似乎返回表达式中的函数声明 (f <- function(){}),同时过滤掉函数调用 ('+'(1,2), ...)。
我想说的是反过来:在该表达式中f
是将被分配给函数的变量(名称)(一旦调用被评估)。+
(1, 2) 计算结果为数字。除非你阻止它这样做。
e <- expression (1 + 2)
> e <- expression (1 + 2)
> e [[1]]
1 + 2
> e [[1]][[1]]
`+`
> class (e [[1]][[1]])
[1] "name"
> eval (e [[1]][[1]])
function (e1, e2) .Primitive("+")
> class (eval (e [[1]][[1]]))
[1] "function"
Run Code Online (Sandbox Code Playgroud)