Reputation: 31
Hi i tried to prepare a little demo code for closures in R when i stumbled into some odd behavior. From using Debug i realize that the failure happens due to the fact that inside of lm this line is being executed
mf <- eval(mf, parent.frame())
however it seems to defeat the functional aspect of programming with closures ?
what am i missing ? here is my little example
# typical closure use
foo <- function(formula,data,weight=NULL) {
if(is.null(weight)) w=ones(nrow(data),1) else w=weight
force(w)
lm(formula,data,weights=w)
}
setup_something <- function(...) {
function(formula,data) {
foo(formula,data,...)
}
}
# set up our model function
model <- setup_something()
# set up our data
df = data.frame(x=seq(1,10,1),y=c(1:10)^1.5 * 3 + 2)
model(y~x,df)
Error in eval(expr, envir, enclos) : object 'w' not found
Upvotes: 2
Views: 199
Reputation: 10167
Instantiating a formula (i.e.x~y
) captures both the environment it is created in, which in your cases happens in the parent.frame()
of your call to model()
.
If you want to subjugate the environment, you can do so explicitly by adding this line right before your call to lm(formula,data,weights=w)
:
# explicitly replace the formula's environment with the current frame
attr(formula,'.Environment') <- sys.frame(sys.nframe())
or implicitly by by replacing your call to lm(formula,data,weights=w)
with:
#instantiate a new forumla based on the existing formula
lm(stats::formula(unclass(formula)),data,weights=w)
By way of background, if you were to stick the following line into lm()
right before the call to mf <- eval(mf, parent.frame())
:
print(ls(envir=parent.frame()))
you would get a list of object names that includes "w"
. However, the 'mf' object being evaluated is a stats::model.frame
thanks to this line:
mf[[1L]] <- quote(stats::model.frame)
and stats::model.frame
evaluates the arguments to mf
in the context of the .Environment
attribute of the formula.
Upvotes: 1