>>>>> Duncan Murdoch <murdoch.dun...@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@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.