Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R: deep copy a function argument

Consider the following code

i = 3
j = i
i = 4 # j != i

However, what I want is

i = 3
f <- function(x, j=i) 
    x * j
i = 4
f(4) # 16, but i want it to be 12

In case you are wondering why I want to do this you could consider this code - the application is a multiple decrements model. The diagonals of a transition matrix are the sum of the other decrements in that row. I would like to define the decrements I need than calculate the other functions using those decrements. In this case, I only need uxt01 and uxt10 and from these I want to produce the functions uxt00 and uxt11. I wanted something that scales to higher dimensions.

Qxt <- matrix(c(uxt00=function(t=0,x=0) 0,
                uxt01=function(t=0,x=0) 0.05,
                uxt10=function(t=0,x=0) 0.07
                uxt11=function(t=0,x=0) 0), 2, 2, byrow=TRUE)

Qxt.diag <- function(Qxt) {
    ndecrements <- length(Qxt[1,])
    for(index in seq(1, N, N+1)) { # 1, 4
        Qxt[[index]] <- function(t=0, x=0, i=index, N=ndecrements) {
            row <- ceiling(index/ndecr)
            row.decrements <- seq( (row - 1)*N + 1, (row)*N) 
            other.decrements <- row.decrements[which(row.decrements != i]
            -sum(unlist(lapply(Qxt.fns[[other.decrements]], 
                function(f) f(t,x))))
        }
    }
    Qxt.fns
}
like image 779
nathanesau Avatar asked Jul 28 '15 20:07

nathanesau


2 Answers

This can be done by assigning the default expression for the formal parameter j manually, after creating the function:

i <- 3;
f <- function(x,j) x*j;
f;
## function(x,j) x*j
formals(f);
## $x
##
##
## $j
##
##
formals(f)$j <- i;
f;
## function (x, j = 3)
## x * j
formals(f);
## $x
##
##
## $j
## [1] 3
##
i <- 4;
f(4);
## [1] 12

This is only possible because R is an awesome language and provides you complete read/write access to all three special properties of functions, which are:

  1. The parse tree that comprises the body: body().
  2. The formal parameters and their default values (which are themselves parse trees): formals().
  3. The enclosing environment (which is used to implement closures): environment().
like image 72
bgoldst Avatar answered Oct 21 '22 15:10

bgoldst


Assign it to a different variable if you want to reuse i:

default_value = i
f = function(x, j = default_value)
    x * j
i = 4
f(4) # 12

of course, you should not let this variable just lying around — that’s as bad as the original code. You can make it “private” to the function, though, by defining both together in a local environment:

f = local({
    default_value = i
    function(x, j = default_value)
        x * j
})
like image 43
Konrad Rudolph Avatar answered Oct 21 '22 17:10

Konrad Rudolph