Here is the rough equivalent to what you did but using the R6 package:

library(R6)

Cache <- R6Class("Cache",
  public = list(
    myCache = numeric(0),
    add = function(x) {
      self$myCache <- c(self$myCache, x)
      print(self$myCache)
    }
  )
)

cacheThis <- Cache$new()

cacheThis$add(17)
cacheThis$add(13)
cacheThis$add(11)

cacheThat <- Cache$new()

cacheThat$add(1)
cacheThat$add(2)
cacheThat$add(3)
cacheThat$add(5)

cacheThis$myCache


It has the same main advantages, the syntax is a little different.
But one nice thing is that you can access the individual caches in a
more simple manner (don't need get, assign, and <<-).  You could make
the cache private instead of public if you want it harder to access
the cache.




On Wed, Mar 23, 2016 at 4:41 PM, Boris Steipe <boris.ste...@utoronto.ca> wrote:
> All -
> Thanks, this has been a real eye-opener.
>
> Here's my variation based on what I've learned so far. It's based on Bert's 
> earlier function-returning-a-closure example. I hope I got the terminology 
> right.
>
> # ========================================================
>
> makeCache <- function(){   # returns a "closure",
>                            # i.e. a function
>                            # plus its private, lexically
>                            # scoped environment
>
>    myCache <- numeric()  # a variable that we want to persist;
>                          # makeCache() creates the
>                          # environment that holds myCache and
>                          # the function useCache() that uses myCache
>
>    useCache <- function(x){
>           myCache <<- c(myCache, x)  # appends a value to myCache
>                                      # <<- does _not_ assign to the
>                                      # global environment, but searches
>                                      # through the parent environments
>                                      # and assigns to the global environment
>                                      # only if no match was found along
>                                      # the way.
>           print(myCache)
>    }
>
>    return(useCache)     # return the function plus its environment
> }
>
> # ======= creating instances of the closure and using them
>
> cacheThis <- makeCache() # cacheThis is the closure that was created
>                          # by makeCache
>
> cacheThis(17)  # 17
> cacheThis(13)  # 17 13
> cacheThis(11)  # 17 13 11
>
>
> cacheThat <- makeCache() # create another closure
>
> cacheThat(1)  # 1
> cacheThat(2)  # 1 2
> cacheThat(3)  # 1 2 3
> cacheThat(5)  # 1 2 3 5
>
> # ======= accessing the private variables
>
> # The caches for cacheThis() and cacheThat() are not visible
> # from the (default) global environment:
> ls()  # [1] "cacheThat" "cacheThis" "makeCache"
>
> # To access them from the global environment, use
> # ls(), exists(), get() and assign(), with their environment
> # argument:
>
> ls.str(envir = environment(cacheThis))
>
> ls.str(envir = environment(cacheThat))
>
> exists("myCache", envir = environment(cacheThat))
> exists("noSuchThing", envir = environment(cacheThat))
>
> # The following won't work - save() needs a name as symbol or string:
> save(get("myCache", envir = environment(cacheThis)), file="myCache.Rdata")
>
> # do this instead:
> tmp <- get("myCache", envir = environment(cacheThis))
> save(tmp, file="myCache.Rdata")
> rm(tmp)
>
> # add a number we don't want...
> cacheThis(6) # 17 13 11 6
>
> # restore cache from saved version
> load("myCache.Rdata") # this recreates "tmp"
> assign("myCache", tmp, envir = environment(cacheThis))
>
> # cache another prime ...
> cacheThis(7) # 17 13 11 7
>
> # etc.
>
> # ========================================================
>
> I don't yet understand the pros and cons of using local() instead of a 
> generating function. From my current understanding, local() should end up 
> doing the same thing - I think that's why Martin calls one a "variant" of the 
> other. But I'll play some more with this later today. Is there a Preferred 
> Way?
>
> memoise has some nice ideas - such as creating a hash from the arguments 
> passed into a function to see if the cached results need to be recomputed. In 
> my use case, I'd like to have more explicit access to the cached results to 
> be able to store, reload and otherwise manipulate them.
>
> I haven't looked at R6 yet.
>
> Cheers,
> Boris
>
>
>
>
>
>
>
>
>
>
>
>
> On Mar 23, 2016, at 5:58 PM, Martin Morgan <martin.mor...@roswellpark.org> 
> wrote:
>
>> 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.



-- 
Gregory (Greg) L. Snow Ph.D.
538...@gmail.com

______________________________________________
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