I'm having trouble of understanding how to work with nested function calls and argument evaluations.
Here's a simple example. I have a top-level function topfunction with one numeric argument. Inside of topfunction I call another function lowerfunction which argument is a call to a function defined inside of 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)
}
Inside of lowerfunction I capture the function call with match.call, and try to evaluate the call. But as variable x is only defined in the environment of topfunction, the evaluation fails:
topfunction(x=1:3)
Error in print(first) : object 'x' not found
I know that I could change the line
lowerfunction(myfun(first=x[1],second=x[2],third=if(length(x)>2) x[3]))
as
lowerfunction(substitute(myfun(first=x[1],second=x[2],third=if(length(x)>2) x[3])))
in topfunction, but in my real application the topfunction is constructed by the user, so the solution should happen somehow in the lowerfunction or even in the myfun level. But as they have already lost the information about x, I don't know if that can be accomplished?
In the real application the topfunction constructs the model using lowerfunction and computes its likelihood, whereas the argument of lowerfunction is a formula which can contain function calls, which will be evaluated via eval. These functions are only defined inside the lowerfunction. Also, lowerfunction can also be called directly, i.e.
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)
So solutions which add x to the argument list of lowerfunction are not applicable in general.
So the problem is that eval should take the definition of myfun from one environment (package namespace, or in this case from the environment of lowerfunction), and evaluate the arguments of myfun in other environment i.e in the environment of topfunction.
myfunis not used directly, it would be better to not export it, but now that I think of it and see how hard it is to use it like I wanted, maybe I'll just export and document it normally.myfunwas probably caused by the fact that its name coindices with the function from base R, so instead of masking issues I thought it would be more clear to just not exportmyfunMaybe I'll just rename my function then.