From murdoch at stats.uwo.ca  Fri Aug 29 13:20:27 2008
From: murdoch at stats.uwo.ca (Duncan Murdoch)
Date: Fri, 29 Aug 2008 07:20:27 -0400
Subject: [Rd] Defining environments within functions
In-Reply-To: <48B7D4DA.7030706@cornell.edu>
References: <48B60482.5010306@cornell.edu> <48B6812E.70809@stats.uwo.ca>
	<48B7D4DA.7030706@cornell.edu>
Message-ID: <48B7DB7B.2060701@stats.uwo.ca>

On 29/08/2008 6:52 AM, Giles Hooker wrote:
> Thanks,
> 
> I think I over-emphasized the secondary function, but I can generate the 
> scoping problem as follows. First, at the command line, I can get a 
> function to access objects that were not in its arguments by
> 
> ProfileEnv = new.env()
> hello.world = "Hello World"
> assign('hello.world',hello.world,3,envir=ProfileEnv)
> 
> fn1 = function()
> {
> 	hw = get('hello.world',envir=ProfileEnv)
> 	print(hw)
> }
> 
> and then call
> 
>  > fn1()
> [1] "Hello World"
> 
> 
> Now I want to define a wrapper function
> 
> fn2 = function()
> {
> 	ProfileEnv = new.env()
> 	hello.world = "Hello World"
> 	assign('hello.world',hello.world,3,envir=ProfileEnv)
> 
> 	fn1()
> }
> 
> and if I try
> 
>  > rm(ProfileEnv)                          # Just to be safe
>  > rm(hello.world)
>  > fn2()
> Error in get("hello.world", envir = ProfileEnv) :
>    object "ProfileEnv" not found

In fn2, you have a local variable called ProfileEnv.  You defined fn1 in 
the global environment, so it can't see it.  Everything would work if 
you defined fn1 within fn2.

A more natural way to do this is not to explicitly use environments. 
Just use the natural lexical scoping in R.  In the example below, I've 
also added a counter variable, to answer your other question.

 > buildfn1 <- function() {
+   hello.world <- "Hello World"
+   counter <- 0
+
+   fn1 <- function() {
+     print(hello.world)
+     counter <<- counter + 1 # note superassignment <<-
+     print(counter)
+   }
+
+   return(fn1)
+ }
 >
 > fn1 <- buildfn1()
 > fn1()
[1] "Hello World"
[1] 1
 > fn1()
[1] "Hello World"
[1] 2

Duncan Murdoch

> 
> In my actual code, fn1() is really a call to
> 
> optim(pars,ProfileErr,....)
> 
> and hello.world are quantities that were calculated the last time that 
> ProfileErr was called and that I want to keep track of.
> 
> As an alternative simple example, how would I keep a counter for the 
> number of times that optim (or any other generic optimizer) has called 
> ProfileErr?
> 
> giles
> 
>>> How can I define environments within a function so that they are visible
>>> to calls to a sub-function?
>>>   
>> I think you need to give a simplified, runnable example.  (Or at least 
>> runnable until it hits the scoping problem you've got.)  "Sub-function" 
>> isn't R terminology, and it's not clear what you mean by it.
>



[Rd] Defining environments within functions
Duncan Murdoch