我正在尝试查找任意合法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"
all.vars(expr,functions = FALSE)似乎在表达式中返回函数声明(f&lt; - function(){}),同时过滤掉函数调用('+'(1,2),... )。
核心库或其他地方是否有任何函数将'this_is_a_function'标记为函数,而不是名称?它需要处理任意表达式,这些表达式在语法上是合法的,但可能无法正确评估(例如'+'(1,'duck'))
我找到similar questions,但它们似乎没有包含解决方案。
如果需要澄清,请在下面留言。我正在使用解析器包来解析表达式。
我的表达式包含整个脚本,通常包含一个包含嵌套函数定义的main函数,并在脚本末尾调用main函数。
函数都是在表达式中定义的,我不介意我是否必须包含'&lt; - '和'{',因为我可以很容易地将它们自己过滤掉。
我的动机是获取所有R脚本,并收集有关我的函数使用方式随时间变化的基本统计信息。
基于Regex的方法获取函数定义,并结合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))
}
答案 0 :(得分:4)
简答: is.function
检查变量是否实际包含函数。这对于(未评估的)呼叫不起作用,因为它们是呼叫。你还需要照顾掩蔽:
mean <- mean (x)
更长的回答:
恕我直言,this_is_a_function
的两次出现有很大的不同。
在第一种情况下,在评估表达式后,您将为名称为this_is_a_function
的变量分配一个函数。差异与2+2
和4
之间的差异相同
但是,仅查找<- function ()
并不能保证结果是函数:
f <- function (x) {x + 1} (2)
第二次出现在语法上是一个函数调用。您可以从表达式中确定需要存在一个包含函数的名为this_is_a_function
的变量,以便正确评估调用。但是:你不知道它是否只存在于该声明中。但是,您可以检查是否存在这样的变量,以及它是否是函数。
函数存储在变量中的事实也像其他类型的数据一样,这意味着在第一种情况下,您可以知道function ()
的结果将是函数,并从中得出结论,紧接在此表达式之后在评估时,名为this_is_a_function
的变量将保存一个函数。
然而,R充满了名称和功能:“ - &gt;”是赋值函数的名称(一个包含赋值函数的变量)......
评估表达式后,您可以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"
all.vars(expr,functions = FALSE)似乎在表达式中返回函数声明(f&lt; - function(){}),同时过滤掉函数调用('+'(1,2),... )。
我会说它是相反的:在那个表达式f
中是变量(name),它将被赋予函数(一旦评估了调用)。 +
(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"
答案 1 :(得分:2)
而不是寻找功能定义,而在没有实际评估函数的情况下实际上无法正确执行,而是更容易查找函数调用。
以下函数递归地捕获表达式/调用树,返回像函数一样调用的所有对象的名称:
find_calls <- function(x) {
# Base case
if (!is.recursive(x)) return()
recurse <- function(x) {
sort(unique(as.character(unlist(lapply(x, find_calls)))))
}
if (is.call(x)) {
f_name <- as.character(x[[1]])
c(f_name, recurse(x[-1]))
} else {
recurse(x)
}
}
对于一个简单的测试用例,它可以正常工作:
x <- expression({
f(3, g())
h <- function(x, y) {
i()
j()
k(l())
}
})
find_calls(x)
# [1] "{" "<-" "f" "function" "g" "i" "j"
# [8] "k" "l"