Is there a way for the R function to determine if it is called from a `for` or` while` loop?

The title of the question pretty much talks about this: is there a way for the R function to find out if it is called directly or from within a for or while ? sys.frame(0) or parent.frame(1) returns .GlobalEnv whether the function was called directly or from within one of these loops. So is there any other way?

Thanks.

+6
source share
4 answers

This is not a definitive answer, but I think your solution would be to look at sys.status , namely sys.parents . The second example is when a function is called inside another function and inside a loop. You don’t know how you distinguish it, not knowing clearly.

 test <- function() sys.status() for(i in 1:2){ print(test()) } ## $sys.calls ## $sys.calls[[1]] ## print(test()) ## ## $sys.calls[[2]] ## test() ## ## $sys.calls[[3]] ## sys.status() ## ## ## $sys.parents ## [1] 0 0 2 ## ## $sys.frames ## $sys.frames[[1]] ## <environment: 0x0479a1c8> ## ## $sys.frames[[2]] ## <environment: 0x0479a2fc> ## ## $sys.frames[[3]] ## <environment: 0x0479a334> ## ## ## $sys.calls ## $sys.calls[[1]] ## print(test()) ## ## $sys.calls[[2]] ## test() ## ## $sys.calls[[3]] ## sys.status() ## ## ## $sys.parents ## [1] 0 0 2 ## ## $sys.frames ## $sys.frames[[1]] ## <environment: 0x047993cc> ## ## $sys.frames[[2]] ## <environment: 0x04799570> ## $sys.frames[[3]] ## <environment: 0x047995a8> 

and

 test() ## $sys.calls ## $sys.calls[[1]] ## test() ## ## $sys.calls[[2]] ## sys.status() ## ## ## $sys.parents ## [1] 0 1 ## ## $sys.frames ## $sys.frames[[1]] ## <environment: 0x04775500> ## ## $sys.frames[[2]] ## <environment: 0x04775538> 

and

 test_sq <- function() test() for(i in 1:2){ print(test_sq()) } ## $sys.calls ## $sys.calls[[1]] ## print(test_sq()) ## ## $sys.calls[[2]] ## test_sq() ## ## $sys.calls[[3]] ## test() ## ## $sys.calls[[4]] ## sys.status() ## ## ## $sys.parents ## [1] 0 0 2 3 ## ## $sys.frames ## $sys.frames[[1]] ## <environment: 0x04766c60> ## ## $sys.frames[[2]] ## <environment: 0x04766dcc> ## ## $sys.frames[[3]] ## <environment: 0x04766e04> ## ## $sys.frames[[4]] ## <environment: 0x04766e3c> ## ## ## $sys.calls ## $sys.calls[[1]] ## print(test_sq()) ## ## $sys.calls[[2]] ## test_sq() ## ## $sys.calls[[3]] ## test() ## ## $sys.calls[[4]] ## sys.status() ## ## ## $sys.parents ## [1] 0 0 2 3 ## ## $sys.frames ## $sys.frames[[1]] ## <environment: 0x04765ac8> ## ## $sys.frames[[2]] ## <environment: 0x04765c34> ## ## $sys.frames[[3]] ## <environment: 0x04765c6c> ## ## $sys.frames[[4]] ## <environment: 0x04765d30> 

and

 test_sq() ## $sys.calls ## $sys.calls[[1]] ## test_sq() ## ## $sys.calls[[2]] ## test() ## ## $sys.calls[[3]] ## sys.status() ## ## ## $sys.parents ## [1] 0 1 2 ## ## $sys.frames ## $sys.frames[[1]] ## <environment: 0x0475ce40> ## ## $sys.frames[[2]] ## <environment: 0x0475cee8> ## ## $sys.frames[[3]] ## <environment: 0x0475cf20> 
+2
source

Unfortunately, for usually does not appear in sys.calls . While hacking it a bit, you can actually override the for , as a result of which it will be turned on:

 `for` = function(iter, vec, expr) eval.parent(replace(sys.call(), 1, list(.Primitive('for')))) in.for = function() '`for`' %in% lapply(sys.calls(), `[[`, 1) my.fun = function() { print('before'); print(in.for()); print('after') } my.fun() # [1] "before" # [1] FALSE # [1] "after" for (x in 1) my.fun() # [1] "before" # [1] TRUE # [1] "after" 
+2
source

Why don't you just use an optional parameter like

 Blah <- function(Param1, OptionalParam = 0){ if(OptionalParam == 1){ #Do This }else{ #Do this } #Everything Else } 
0
source

Unfortunately, it was premature. It turns out that the index variable is saved after the for() loop. Heck.

Hm! I already have a function that replaces an arbitrary string in a function with the contents of a variable:

 replaceincall <- function(xx,from,to){ # from is a string, to is a name if(is.name(xx)){ ifelse(as.character(xx)==from,return(to),return(xx)); } else { if(is.call(xx)) { oo <- lapply(as.list(xx),function(yy) replaceincall(yy,from,to)); return(as.call(oo)); } else { return(xx); } } } 

In my overloaded function <<- I also already extract a list of names from sys.call() that do not correspond to the functions. This means that they are some kind of variable. All I have to do is find those that are not in ls(.GlobalEnv) , and they should be those that are index variables, and they should be replaced with their values ​​in the log entry (using the function above) .

Now it can catch and replace stuff besides loops ... but maybe it's good, because, regardless of the reason the variable is not in .GlobalEnv , it is still a dynamic variable and therefore someday, when I look through a magazine I’m going to wonder how to restore it if I don’t fix its value right now.

Does anyone see flaws in this reasoning?

0
source

Source: https://habr.com/ru/post/922185/


All Articles