Reputation: 442
I have strange environment/scoping dynamic that I've been trying to figure out, and looking for the right or recommended method for achieving this.
I've made a toy example of my problem below purely for illustration. (I'm aware this particular problem can be solved much more simply, but it illustrates the dynamic I'm trying to implement).
Current functioning code:
master_function <-
function(x, iter = 100){
x_p1 <- function(){ x <<- x + 1 }
x_m1 <- function(){ x <<- x - 1 }
path <- numeric(iter)
for(i in 1:iter){
next_step <- sample(c('p', 'm'), 1)
if(next_step == 'p'){
x_p1()
} else {
x_m1()
}
path[i] <- x
}
path
}
The issue with this code (especially for an actually difficult problem) is that it makes debugging the x_p1
, x_m1
function contents with the RStudio debug utility impossible.
Hoping to restructure the code to look something like:
master_function <-
function(x, iter = 100){
master_env <- environment()
path <- numeric(iter)
for(i in 1:iter){
next_step <- sample(c('p', 'm'), 1)
if(next_step == 'p'){
x_p1(master_env)
} else {
x_m1(master_env)
}
path[i] <- x
}
path
}
x_p1 <- function(env){ assign('x', get('x', envir = env) + 1, envir = env) }
x_m1 <- function(env){ assign('x', get('x', envir = env) - 1, envir = env) }
But this is also quite ugly. Is there a way to augment the search path, for example, such that access to the master_env
is cleaner?
Edit: More information as requested by @MrFlick
Essentially I have simulation with a lot of moving pieces. As it progresses, different events (the sub-functions being referenced) are triggered modifying the state of the simulation. These functions currently modify many different state objects for each function call. Since the functions are made within the master function call, I can take advantage of lexical scoping and the <<-
operator, but I lose the ability to debug within those functions.
Trying to figure out how to create those functions outside of the master simulation. If I understand correctly, if I make the functions such that they consume the simulation state and return a modified version, it comes at a large memory cost.
Upvotes: 1
Views: 53
Reputation: 270298
1) trace Use trace
to insert debug
statements after the definitions of x_p1
and x_m1
and then one can step through them when master_function
is run.
trace(master_function, at = 4, quote({debug(x_p1); debug(x_m1) }))
untrace(master_function)
turns this off. Use body(master_function)[4]
to see which line corresponds to 4. See ?trace
for more.
2) instrument Another possibility is to instrument your function like this and then call it with master(function(x, DEBUG = TRUE)
to turn on debugging.
master_function <-
function(x, iter = 100, DEBUG = FALSE){
x_p1 <- function(){ x <<- x + 1 }
x_m1 <- function(){ x <<- x - 1 }
if (DEBUG) {
debug(x_p1)
debug(x_m1)
}
path <- numeric(iter)
for(i in 1:iter){
next_step <- sample(c('p', 'm'), 1)
if(next_step == 'p'){
x_p1()
} else {
x_m1()
}
path[i] <- x
}
path
}
Upvotes: 2
Reputation: 2445
Why does x need to reside in an alternative environment at all? The following internalizes and avoids the multiple environments entirely.
x_p1 <- function(z){ z + 1 }
x_m1 <- function(z){ z - 1 }
master_function <-
function(x, iter = 100){
new_x <- x
path <- numeric(iter)
for(i in 1:iter){
next_step <- sample(c('p', 'm'), 1)
if(next_step == 'p'){
new_x <- x_p1(new_x)
} else {
new_x <- x_m1(new_x)
}
path[i] <- new_x
}
path
}
Upvotes: 1