Accessing a function's environment

Douglas Bates bates@stat.wisc.edu
15 Jun 1999 13:35:39 -0500


In a short course he is teaching here, Bill Venables has shown how to
cache the results of a recursive calculation so that later invocations
of the functions are speeded up.  His example is an ingenious way of
calculating all the subsets of size r from a set of size n.

His version of this function for R stored these cached values in the
global environment.  I suggested that it might be preferable to
declare the function in such a way that it carried an environment with
it and to use that environment for caching.

For illustration, I will show a factorial function that uses this
trick.  I use .env to store the environment in which the function was
defined then put the cached results in that environment.  Is there a
cleaner way to get the environment in which the currently executing
function was defined?  Sometimes (as below) you do not know the name
under which the function will be stored so you can't use something
like environment(Fact).  Just as "Recall" means to call myself again
regardless of the name, is there a way of a function getting the
environment in which it was defined without knowing its own name?

 > mkFact        # a function that constructs a factorial function
 function () 
 {
     .env <- environment()
     function(n) {
	 nm <- paste(".", n, sep = "/")
	 if (n <= 0) 
	     return(1)
	 if (exists(nm, envir = .env)) 
	     return(get(nm, envir = .env))
	 ans <- n * Recall(n - 1)
	 assign(nm, ans, envir = .env)
	 ans
     }
 }
 > Fact <- mkFact()
 > Fact         # the actual factorial function with an environment
 function (n) 
 {
     nm <- paste(".", n, sep = "/")
     if (n <= 0) 
	 return(1)
     if (exists(nm, envir = .env)) 
	 return(get(nm, envir = .env))
     ans <- n * Recall(n - 1)
     assign(nm, ans, envir = .env)
     ans
 }
 <environment: 0x406136e0>
 > Fact(4)
 [1] 24
 > objects(env = environment(Fact), all = TRUE)
 [1] "./1"  "./2"  "./3"  "./4"  ".env"
 > Fact(6)
 [1] 720
 > objects(env = environment(Fact), all = TRUE)
 [1] "./1"  "./2"  "./3"  "./4"  "./5"  "./6"  ".env"

If you use debug(Fact) and check what happens when Fact(6) is
evaluated, you will see that by the time it evaluates Fact(4), it
picks up the result from the environment.
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !)  To: r-devel-request@stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._