简体   繁体   中英

Forcing a function definition to evaluate a symbol

Consider the example below:

> x=2
> myfun = function(y) x*y
> myfun(3)
[1] 6
> x=4
> myfun(3)
[1] 12

How would I have to define myfun so that its definition keeps the value of x such as it is at the time of definition, rather than a reference to x ? (ie, that the second call myfun(3) also yields 6 rather than 12).

EDIT: changed the title to remove incorrect terminology.

I have to guess a little bit what your purpose is. Perhaps you simply need to define one of your arguments with a default value:

myfun <- function(y, x=2){
  x * y
}

Then use it:

x <- 3

myfun(4)
[1] 8

myfun(x=4, 3)
[1] 12

myfun(x)
[1] 6

But perhaps you really are describing a closure.

An object is data with functions. A closure is a function with data.

--- John D Cook

Here is an example. First define a closure that remembers a snapshot:

newSnapshot <- function(x){
  xx <- x
  function(y) xx * y
}

Then use it:

x <- 10
myfun <- newSnapshot(x)

myfun(4)
[1] 40

x <- 4
myfun(5)
[1] 50

Almost the same question was asked on the R-help mailing list yesterday. See the discussion on Nabble for the various ways you can do that.

http://r.789695.n4.nabble.com/Force-evaluation-of-a-symbol-when-a-function-is-created-td4639350.html

And here are three ways to do it (gathered from the R-help discussion):

x <- 2

f1 <- local({x.now <- x;function(y) x.now*y})
f2 <- evalq(function(y)a*y,env=list(a=x))

multiply_by_x <- function(x) {
    force(x)
    function(y) y*x
}

f3 <- multiply_by_x(x)

with results

> f1(3)
[1] 6
> f2(3)
[1] 6
> f3(3)
[1] 6

> x <- 4
> f1(3)
[1] 6
> f2(3)
[1] 6
> f3(3)
[1] 6

One approach is this:

myfun <- function(x = 2) {
    function(y) {
        x * y
    }
}

Basically we write a function that returns a function that does the computation we want. In the above x is set to 2 by default but you can vary this when you call myfun . When we call myfun() we save the returned function, in foo in the example below:

> foo <- myfun()

Now, no matter what you do to x in the global environment foo() will always use the value of x that was defined in the environment of myfun() when that function was called.

> foo(3)
[1] 6
> x <- 6
> foo(3)
[1] 6
> x <- 4
> foo(3)
[1] 6

This all works because the environment of the function created by the call to myfun() contains x and that x has the value of x that was present when the function was defined.

> environment(foo)$x
[1] 2

Here's another closure solution:

myfun <- local({
  x <- 2
  list(
    f=function(y) {
      x*y
    },
    set.x=function(newx) {
      x <<- newx
    },
    get.x=function() {
      x
    }
  )
})

Then you can use it as follows:

> myfun$get.x()
[1] 2
> myfun$set.x(5)
> myfun$get.x()
[1] 5
> myfun$f(3)
[1] 15

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