如何在R中的其他函数内计算函数调用的参数

Jou*_*ske 6 arguments r function lazy-evaluation

我无法理解如何使用嵌套函数调用和参数评估.

这是一个简单的例子.我有一个topfunction带有一个数字参数的顶级函数.在topfunction我内部调用另一个函数lowerfunction,该参数是对内部定义的函数的调用lowerfunction.

topfunction<-function(x){  
  lowerfunction(myfun(first=x[1],second=x[2],third=if(length(x)>2) x[3]))
}

lowerfunction<-function(mycall){ 

  myfun<-function(first,second=0,third=NULL){
    print(first)
    print(second)
    print(third)
  }

  mc<-match.call(definition = myfun, call = match.call()[[2]]) 
  eval(mc) 
}
Run Code Online (Sandbox Code Playgroud)

lowerfunction我在里面捕获函数调用match.call,并尝试评估调用.但由于变量x仅在环境中定义topfunction,评估失败:

topfunction(x=1:3)
Error in print(first) : object 'x' not found
Run Code Online (Sandbox Code Playgroud)

我知道我可以换线

lowerfunction(myfun(first=x[1],second=x[2],third=if(length(x)>2) x[3]))
Run Code Online (Sandbox Code Playgroud)

lowerfunction(substitute(myfun(first=x[1],second=x[2],third=if(length(x)>2) x[3])))
Run Code Online (Sandbox Code Playgroud)

in topfunction,但在我的实际应用程序中topfunction由用户构建,因此解决方案应该以某种方式发生在lowerfunction甚至是myfun级别中.但由于他们已经丢失了相关信息x,我不知道是否可以实现这一目标?

在实际应用程序中,topfunction构造模型使用lowerfunction并计算其可能性,而参数lowerfunction是一个可以包含函数调用的公式,将通过它来计算eval.这些功能仅在内部定义lowerfunction.另外,lowerfunction也可以直接调用,即

x<-1:3
lowerfunction(myfun(first=x[1],second=x[2],third=if(length(x)>2) x[3]))
# or
lowerfunction(myfun(first=x1,second=2)
Run Code Online (Sandbox Code Playgroud)

因此,添加x到参数列表中的解决方案lowerfunction通常不适用.

所以问题是eval应该myfun从一个环境(包命名空间,或者在这种情况下从环境中lowerfunction)定义,并评估myfun其他环境中的参数,即在环境中topfunction.

had*_*ley 5

这是一个相对简单的问题,但由于您正在进行非常非标准的评估,因此您需要创建一个新环境,并确保您需要的所有对象都可以从该环境访问。

g <- function(x){  
  f1(f2(x[1], x[2], if(length(x) > 2) x[3]))
}

f1 <- function(mycall, parent = parent.frame()) {
  # Parent contains x
  # New environment that contains f2 and inherits from the parent
  env <- new.env(parent = parent)
  env$f2 <- function(first, second = 0,third = NULL) {
    print(first)
    print(second)
    print(third)
  }

  # More idiomatic way of getting unevaluated expression
  expr <- substitute(mycall)
  eval(expr, env)
}

g(1:3)
Run Code Online (Sandbox Code Playgroud)

我在我的领域特定语言一章中描述了类似的技术