简体   繁体   中英

Using current value of global variable in function definition

I have a global variable x and want to build a function f that returns the value of x at the time the function is created. Example:

x <- 5
f <- function() return(x)
f()
> 5
x <- 10
f()
> 10 # Should return 5

I want a function that always return 5 (or whatever the value of x is at the time of function creation) without using another global variable. Is that possible?

Still another option using body :

f<-`body<-`(function() {},value=x)

Example:

x<-10
f<-`body<-`(function() {},value=x)
f()
#[1] 10
x<-100
f()
#[1] 10

Digging the source code of body , here is an even cleaner solution equivalent to the above using as.function :

f<-as.function(list(x))

This is not possible with global variables alone. When a function is defined, none of the variables in the function body are actually evaluated till the function is called. What you want seems to be a closure to hold the value at the time of creation. Instead write a function that returns a function

x <- 5
getfun <- function() {z<-x; function() return(z)}
f <- getfun()
x<- 10
g <- getfun()
f()
# [1] 5
g()
# [1] 10

Or even better, don't implicitly use global variables. Create a function that takes a certain set of parameters and returns a new function

returnVal <- function(x) {force(x); function() return(x)}
f<-returnVal(5)
g<-returnVal(10)
f()
# [1] 5
g()
# [1] 10

1) This saves the value of x the first time f is called and then uses that value of x even if x has been changed the next time f is called. Create f in a local environment and have f place x in that environment. If x was not previously there it will now be. If it was previously there then it will be the x retrieved and placed back. The result is that the first x encountered will always be used.

f <- local(function() {
      p <- parent.env(environment())
      p$x <- x
      x
})


x <- 5
f()
## [1] 5
x <- 10
f()
## [1] 5

2) In comments @Konrad and @Frank have suggested the following variation in which we remove the assignment from f and put it in the local.

There is one difference from the viewpoint of the user of the function. This instantiates the value of x at the time the function is defined whereas (1) instantiates x the first time that the function is called and that might be an advantage if you want to separate the definition and the instantiation.

x <- 5
f <- local({ x <- x; function() x })
f()
## [1] 5
x <- 10
f()
## [1] 5

3) We can also consider completely separating the function from the instantiation. This would also allow re-initialization at any time by calling e$init() again.

e <- local({
        init <- function() {
           p <- parent.env(environment())
           p$x <- x
        }
        run = function() x
        environment()
   })

x <- 5
e$init()
e$run()
## [1] 5

x <- 10
e$run()
## [1] 5

4) (3) could be implemented using a variety of object oriented frameworks such as Reference Classes, proto or R6. In proto it would be like this:

library(proto)

p <- proto(init = function(.) .$x <- x, run = function(.) x)

x <- 5
p$init()
p$run()
## [1] 5

x <- 10
p$run()
## [1] 5

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM