From luke at stat.uiowa.edu  Fri Aug 29 15:44:29 2008
From: luke at stat.uiowa.edu (Luke Tierney)
Date: Fri, 29 Aug 2008 08:44:29 -0500 (CDT)
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: <alpine.LFD.1.10.0808290841190.3121@nokomis.stat.uiowa.edu>

If you want to use this pattern repeatedly you can define something like

     makeFunWithCounter <- function(fun) {
 	counter <- 0
 	list(count = function() counter,
 	     fun = function(...) { counter <<- counter + 1; fun(...)})
     }

and then do

     > fwc <- makeFunWithCounter(function() print("Hello"))
     > f2 <- fwc$fun
     > f2()
     [1] "Hello"
     > f2()
     [1] "Hello"
     > f2()
     [1] "Hello"
     > fwc$count()
     [1] 3

If you only want to do it once you can use local,

     fwc <- local({
 	counter <- 0
 	fun <- function() { counter <<- counter + 1; print("Hello") }
 	list(count = function() counter, fun = fun)
     })

Best,

luke

On Fri, 29 Aug 2008, 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 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.
>
>

-- 
Luke Tierney
Chair, Statistics and Actuarial Science
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:      luke at stat.uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu



[Rd] Defining environments within functions
Luke Tierney