在 R 表达式中查找所有函数的名称

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'))

我发现了类似的问题,但它们似乎不包含解决方案。

如果需要澄清,请在下面发表评论。我正在使用解析器包来解析表达式。

编辑:@Hadley

我有包含整个脚本的表达式,这些脚本通常由一个包含嵌套函数定义的 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)

cbe*_*ica 4

简短的回答: 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)