Update 2 @G. Grothendieck posted two approaches. The second one is changing the function environment inside a function. This solves my problem of too many coding replicates. I am not sure if this is a good method to pass through the CRAN check when making my scripts into a package. I will update again when I have some conclusions.
Update
I am trying to pass a lot of input argument variables to f2
and do not want to index every variable inside the function as env$c, env$d, env$calls
, that is why I tried to use with
in f5
and f6
(a modified f2
). However, assign
does not work with with
inside the {}
, moving assign
outside with
will do the job but in my real case I have a few assign
s inside the with
expressions which I do not know how to move them out of the with
function easily.
Here is an example:
## In the <environment: R_GlobalEnv>
a <- 1
b <- 2
f1 <- function(){
c <- 3
d <- 4
f2 <- function(P){
assign("calls", calls+1, inherits=TRUE)
print(calls)
return(P+c+d)
}
calls <- 0
v <- vector()
for(i in 1:10){
v[i] <- f2(P=0)
c <- c+1
d <- d+1
}
return(v)
}
f1()
Function f2
is inside f1
, when f2
is called, it looks for variables calls,c,d
in the environment environment(f1)
. This is what I wanted.
However, when I want to use f2
also in the other functions, I will define this function in the Global environment instead, call it f4
.
f4 <- function(P){
assign("calls", calls+1, inherits=TRUE)
print(calls)
return(P+c+d)
}
This won't work, because it will look for calls,c,d
in the Global environment instead of inside a function where the function is called. For example:
f3 <- function(){
c <- 3
d <- 4
calls <- 0
v <- vector()
for(i in 1:10){
v[i] <- f4(P=0) ## or replace here with f5(P=0)
c <- c+1
d <- d+1
}
return(v)
}
f3()
The safe way should be define calls,c,d
in the input arguments of f4
and then pass these parameters into f4
. However, in my case, there are too many variables to be passed into this function f4
and it would be better that I can pass it as an environment and tell f4
do not look in the Global environment(environment(f4)
), only look inside the environment
when f3
is called.
The way I solve it now is to use the environment as a list and use the with
function.
f5 <- function(P,liste){
with(liste,{
assign("calls", calls+1, inherits=TRUE)
print(calls)
return(P+c+d)
}
)
}
f3 <- function(){
c <- 3
d <- 4
calls <- 0
v <- vector()
for(i in 1:10){
v[i] <- f5(P=0,as.list(environment())) ## or replace here with f5(P=0)
c <- c+1
d <- d+1
}
return(v)
}
f3()
However, now assign("calls", calls+1, inherits=TRUE)
does not work as it should be since assign
does not modify the original object. The variable calls
is connected to an optimization function where the objective function is f5
. That is the reason I use assign
instead of passing calls
as an input arguments. Using attach
is also not clear to me. Here is my way to correct the assign
issue:
f7 <- function(P,calls,liste){
##calls <<- calls+1
##browser()
assign("calls", calls+1, inherits=TRUE,envir = sys.frame(-1))
print(calls)
with(liste,{
print(paste('with the listed envrionment, calls=',calls))
return(P+c+d)
}
)
}
########
##################
f8 <- function(){
c <- 3
d <- 4
calls <- 0
v <- vector()
for(i in 1:10){
##browser()
##v[i] <- f4(P=0) ## or replace here with f5(P=0)
v[i] <- f7(P=0,calls,liste=as.list(environment()))
c <- c+1
d <- d+1
}
f7(P=0,calls,liste=as.list(environment()))
print(paste('final call number',calls))
return(v)
}
f8()
I am not sure how this should be done in R. Am I on the right direction, especially when passing through the CRAN check? Anyone has some hints on this?
f2
, i.e, not writingenv$
, that is why I tried to usewith
. I want to be able to modify the outsidecalls
insidef2
but not changing the other variables in the current environment. I will update the question. – Panhellenism