Last chance! 50% off unlimited learning
Sale ends in
mlocal
lets you write a function whose statements are executed in its caller's frame, rather than in its own frame.# Use only as wrapper of function body, like this:
# my.fun <- function(..., nlocal=sys.parent()) mlocal( expr)
# ...should be replaced by the arguments of "my.fun"
# expr should be replaced by the code of "my.fun"
# nlocal should always be included as shown
mlocal( expr) # Don't use it like this!
local.return
.assign
or <<-< code=""> (note that <<-< code=""> will only work on variables that exist already). This can make for clearer, more modular programming; for example, tedious initializations of many variables can be hidden inside an initialize()
statement. The definition of an mlocal
function does not have to occur within its caller; the mlocal
function can exist as a completely separate Robject.
mlocal
functions can have arguments just like normal functions. These arguments will temporarily hide any objects of the same name in the nlocal
frame (i.e. the calling frame). When the mlocal
function exits, its arguments will be deleted from the calling frame and the hidden objects (if any) will be restored. Sometimes it's desirable to avoid cluttering the calling frame with variables that only matter to the mlocal
function. A useful convention is to "declare" such temporary variables in your function definition, as defaultless arguments after the nlocal
argument.
The nlocal
argument of an mlocal
function-- which must ALWAYS be included in the definition, with the default specified as sys.parent()
-- can normally be omitted when invoking your mlocal
function. However, you will need to set it explicitly when your function is to be called by another, e.g. lapply
; see the third example. A more daring usage is to call e.g. fun.mlocal(nlocal=another.frame.number)
so that the statements in fun.mlocal
get executed in a completely different frame. A convoluted example can be found in the (internal) function find.debug.HQ
in the debug package, which creates a frame and defines a large number of variables in it, by calling setup.debug.admin(nlocal=new.frame.number)
.
mlocal
functions can be nested, though this gets confusing. By default, all evaluation will happen in the same frame.
Note that (at least at present) all arguments are evaluated as soon as your mlocal
function is invoked, rather than by the usual lazy evaluation mechanism. Missing arguments are still OK, though.
If you call return
in an mlocal
function, you must call local.return
too.
Frame-dependent functions (sys.parent()) etc. will not do what you expect inside an mlocal
function. In R1.8 at least, you need to shift the normal index by 3 to get what you'd expect, so that sys.call(-3)
inside an mlocal
function will return the call to the mlocal
function, and sys.function( sys.parent(3))
will return the mlocal
function definition. You can get the expected results for the caller via mvb.sys.parent
with no shift, etc.-- unless the caller is itself an mlocal
function.
on.exit
doesn't work properly, contrary to what previous mlocal
documentation said (the scoping is wrong, though often this doesn't matter). If you want to have exit code in the mlocal
function itself, use local.on.exit
. I can't find any way to set the exit code in the calling function from within an mlocal
function.
See R-news 2001 #3 (1/3) for another closely related approach to "macros".
local.return
, local.on.exit
, do.in.envir
, and R-news 1/3# Tidiness and variable creation
init <- function( nlocal=sys.parent()) mlocal( sqr.a <- a*a)
ffout <- function( a) { init(); sqr.a }
ffout( 5) # 25
# Parameters and temporary variables
ffin <- function( n, nlocal=sys.parent(), a, i) mlocal({
# this "n" and "a" will temporarily replace caller's "n" and "a"
print( n)
a <- 1
for( i in 1:n)
a <- a*x
a
})
x.to.the.n.plus.1 <- function( x, n) {
print( ffin( n+1))
print( n)
print( ls())
}
x.to.the.n.plus.1( 3, 2) # prints as follows:
# [1] 3 (in "ffin")
# [1] 27 (result of "ffin")
# [1] 2 (original n)
# [1] "n" "x" (vars in "x.to.the\dots"-- NB no a or i)
# Use of "nlocal"
ffin <- function( i, nlocal=sys.parent()) mlocal( a <- a+i )
ffout <- function( ivec) { a <- 0; sapply( ivec, ffin, nlocal=sys.nframe()) }
ffout( 1:3) # 1 3 6
Run the code above in your browser using DataLab