Use a local environment to as a place to store state. Update with <<- and resolve symbol references through lexical scope E.g.,

    persist <- local({
        last <- NULL                # initialize
        function(value) {
            if (!missing(value))
                last <<- value      # update with <<-
            last                    # use
        }
    })

and in action

> persist("foo")
[1] "foo"
> persist()
[1] "foo"
> persist("bar")
[1] "bar"
> persist()
[1] "bar"

A variant is to use a 'factory' function

    factory <- function(init) {
        stopifnot(!missing(init))
        last <- init
        function(value) {
            if (!missing(value))
                last <<- value
            last
        }
    }

and

> p1 = factory("foo")
> p2 = factory("bar")
> c(p1(), p2())
[1] "foo" "bar"
> c(p1(), p2("foo"))
[1] "foo" "foo"
> c(p1(), p2())
[1] "foo" "foo"

The 'bank account' exercise in section 10.7 of RShowDoc("R-intro") illustrates this.

Martin

On 03/19/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])))
}


Thanks!
Boris

______________________________________________
R-help@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.



This email message may contain legally privileged and/or confidential 
information.  If you are not the intended recipient(s), or the employee or 
agent responsible for the delivery of this message to the intended 
recipient(s), you are hereby notified that any disclosure, copying, 
distribution, or use of this email message is prohibited.  If you have received 
this message in error, please notify the sender immediately by e-mail and 
delete this email message from your computer. Thank you.

______________________________________________
R-help@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.

Reply via email to