[R] Persistent state in a function?

Bert Gunter bgunter.4567 at gmail.com
Mon Mar 21 17:06:22 CET 2016


Yes, Duncan.  My statement was wrong. I should have said that it's the
environment/evaluation frame of f = g(). Thank you for the correction.
Still, I hope my example was helpful.

Cheers,
Bert


Bert Gunter

"The trouble with having an open mind is that people keep coming along
and sticking things into it."
-- Opus (aka Berkeley Breathed in his "Bloom County" comic strip )


On Mon, Mar 21, 2016 at 8:30 AM, Duncan Murdoch
<murdoch.duncan at gmail.com> wrote:
> On 21/03/2016 11:19 AM, Bert Gunter wrote:
>>
>> Martin, All:
>>
>> A very nice point! Perhaps the following may help to illustrate it.
>>
>> g <- function(){
>>    x <- NULL
>>    function(y){cat("result is ",x," \n"); x <<- y}
>> }
>>
>>
>> > f <- g()
>>
>> > rm(g) # g is deleted but its environment remains as the environment of f
>
>
> That's not quite the jargon we use.  The environment of g would probably be
> the global environment.  The thing that gets left behind is the evaluation
> frame (or environment) of the call g().  Its parent environment is the
> environment of g.
>
> Duncan Murdoch
>>
>>
>> > f(1)
>> result is
>>
>> > f(3)
>> result is  1
>>
>> > f(5)
>> result is  3
>>
>>
>> Best,
>> Bert
>>
>>
>>
>>
>>
>> Bert Gunter
>>
>> "The trouble with having an open mind is that people keep coming along
>> and sticking things into it."
>> -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip )
>>
>>
>> On Mon, Mar 21, 2016 at 2:41 AM, Martin Maechler
>> <maechler at stat.math.ethz.ch> wrote:
>> >>>>>> Duncan Murdoch <murdoch.duncan at gmail.com>
>> >>>>>>     on Sat, 19 Mar 2016 17:57:56 -0400 writes:
>> >
>> >     > On 19/03/2016 12:45 PM, Boris Steipe wrote:
>> >     >> Dear all -
>> >     >>
>> >     >> I need to have a function maintain a persistent lookup table of
>> > results for an expensive calculation, a named vector or hash. I know that I
>> > can just keep the table in the global environment. One problem with this
>> > approach is that the function should be able to delete/recalculate the table
>> > and I don't like side-effects in the global environment. This table really
>> > should be private. What I don't know is:
>> >     >> -A- how can I keep the table in an environment that is private to
>> > the function but persistent for the session?
>> >     >> -B- how can I store and reload such table?
>> >     >> -C- most importantly: is that the right strategy to initialize
>> > and maintain state in a function in the first place?
>> >     >>
>> >     >>
>> >     >> For illustration ...
>> >     >>
>> >     >> -----------------------------------
>> >     >>
>> >     >> myDist <- function(a, b) {
>> >     >> # retrieve or calculate distances
>> >     >> if (!exists("Vals")) {
>> >     >> Vals <<- numeric() # the lookup table for distance values
>> >     >> # here, created in the global env.
>> >     >> }
>> >     >> key <- sprintf("X%d.%d", a, b)
>> >     >> thisDist <- Vals[key]
>> >     >> if (is.na(thisDist)) {          # Hasn't been calculated yet ...
>> >     >> cat("Calculating ... ")
>> >     >> thisDist <- sqrt(a^2 + b^2) # calculate with some expensive
>> > function ...
>> >     >> Vals[key] <<- thisDist      # store in global table
>> >     >> }
>> >     >> return(thisDist)
>> >     >> }
>> >     >>
>> >     >>
>> >     >> # run this
>> >     >> set.seed(112358)
>> >     >>
>> >     >> for (i in 1:10) {
>> >     >> x <- sample(1:3, 2)
>> >     >> print(sprintf("d(%d, %d) = %f", x[1], x[2], myDist(x[1], x[2])))
>> >     >> }
>> >
>> >
>> >     > Use local() to create a persistent environment for the function.
>> > For
>> >     > example:
>> >
>> >     > f <- local({
>> >     > x <- NULL
>> >     > function(y) {
>> >     > cat("last x was ", x, "\n")
>> >     > x <<- y
>> >     > }
>> >     > })
>> >
>> >     > Then:
>> >
>> >     >> f(3)
>> >     > last x was
>> >     >> f(4)
>> >     > last x was  3
>> >     >> f(12)
>> >     > last x was  4
>> >
>> >     > Duncan Murdoch
>> >
>> > Yes, indeed.
>> > Or use another function {than 'local()'} which returns a
>> > function:  The functions  approxfun(), splinefun() and ecdf()
>> > are "base R" functions which return functions "with a
>> > non-trivial environment" as I use to say.
>> >
>> > Note that this is *the* proper R way solving your problem.
>> >
>> > The fact that this works as it works is called "lexical scoping"
>> > and also the reason why (((regular, i.e., non-primitive)))
>> > functions in R are called closures.
>> > When R was created > 20 years ago, this has been the
>> > distinguishing language feature of R (in comparison to S / S-plus).
>> >
>> > Enjoy! - Martin
>> >
>> > ______________________________________________
>> > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>> > https://stat.ethz.ch/mailman/listinfo/r-help
>> > PLEASE do read the posting guide
>> > http://www.R-project.org/posting-guide.html
>> > and provide commented, minimal, self-contained, reproducible code.
>
>



More information about the R-help mailing list