Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way for an R function to tell if it's being called from a `for` or `while` loop?

The title of the question pretty much says it: is there a way for an R function to find out if it is being called directly or from inside a for or while loop? sys.frame(0) or parent.frame(1) returns .GlobalEnv whether the function was called directly or from inside one of those loops. So, is there some other way?

Thanks.

like image 622
bokov Avatar asked Aug 06 '12 01:08

bokov


2 Answers

This is not a definitive answer, but I think your solution will be to look at the sys.status, specifically the sys.parents. The second example is for when the function is called within another function, and within a loop. Not sure how you differentiate this without knowing explicitly.

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>
like image 167
mnel Avatar answered Oct 13 '22 05:10

mnel


Unfortunately for doesn't appear in sys.calls normally. While its a bit of a hack, you can actually override for, causing it to be included:

`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"
like image 30
Charles Avatar answered Oct 13 '22 04:10

Charles