Limiting variable scope

2019-01-07 23:32发布

I'm trying to write a function, which limits the scope of R variables. For example,

source("LimitScope.R")
y = 0
f = function(){
   #Raises an error as y is a global variable
   x = y
}

I thought of testing the variable environment, but wasn't really sure of how to do this.

The why

I teach R to undergrads. In their first couple of practicals a few of them always forget about variable scope, so their submitted functions don't work. For example, I always get something like:

n = 10
f = function(x){
  #Raises an error
  #as I just source f and test it for a few test cases.
  return(x*n)
}

I was after a quick function that would 'turn off' scope. As you can imagine it doesn't have to be particularly robust, as it would just be offered for the few practicals.

标签: r scope
4条回答
疯言疯语
2楼-- · 2019-01-08 00:04

I'm not sure that you want to do this in general, but the local() function should help, as should the codetools library.

In your example, try

f = local( function() { ... }, baseenv())

It does not do exactly what you want, but it should get you closer.

查看更多
Fickle 薄情
3楼-- · 2019-01-08 00:06

You can check if y exists in the global environment using exists('y',envir=.GlobalEnv)

查看更多
爷的心禁止访问
4楼-- · 2019-01-08 00:06

What occassionally happens to me is that I've got a split screen in ESS with a file buffer of R code on the left and the interpreter on the right. I may have set some values in the interpreter while I debug the code I am working on in the buffer. It's then possible that the code in the buffer accidentally refereneces something I set in the intepreter. That's hard to detect problem unless I evaluate my buffer in a fresh interpreter every time, which is not how ESS works by default.

If this is the kind of problem you are seeing frequently, an rm(list=ls(envir=.GlobalEnv)) in the thing you source might help, but that of course creates other issues, such as erasing anything they were using to keep state while debugging, etc.

查看更多
甜甜的少女心
5楼-- · 2019-01-08 00:14

You can force a variable to be the local version with this function:

get_local <- function(variable)
{
  get(variable, envir = parent.frame(), inherits = FALSE)  
}

Compare these cases

y <- 0    
f <- function()
{
  x <- y
}    
print(f())        # 0

y <- 0    
f <- function()
{
  y <- get_local("y")
  x <- y
}    
print(f())        # Error: 'y' not found

Depending on what you are doing, you may also want to check to see if y was an argument to f, using formalArgs or formals.

g  <- function(x, y = TRUE, z = c("foo", "bar"), ...) 0

formalArgs(g)
# [1] "x"   "y"   "z"   "..."

formals(g)
#$x
#
#
#$y
#[1] TRUE
#
#$z
#c("foo", "bar")
#
#$...

EDIT: The more general point of 'how to turn off lexical scoping without changing the contents of functions' is harder to solve. I'm fairly certain that the scoping rules are pretty ingrained into R. An alternative might be to use S-Plus, since it has different scoping rules.

查看更多
登录 后发表回答