memoise
memoise copied to clipboard
unmemoise function?
Firstly, this package is really great! Thanks for the development and support. I'm writing to see if there'd be interest in an unmemoise(fn)
function which will then make sure that this will work:
fn <- memoise(fn)
is.memoised(fn) # TRUE
unmemoise(fn)
is.memoised(fn) # FALSE
A usecase for this would be for example an interactive session where larger requests to the same functions might be suitable for caching but more granular requests might be better off run on real time data.
Has there been already any thought on such feature?
R's semantics don't really support your example, you would have to fn <- unmemoise(fn)
.
The original function is stored in the memoized function's environment, so you can call that.
environment(fn)`_f`()
But if you don't want memoization why wouldn't you just call the original function directly?
@jimhester I hope I am not adding noise to this discussion, but what about the following scenarios, where it would be desirable to temporarily switch off memoisation (while retaining the existing cache for later use)?:
- You want a specific call to adhere to lazy evaluation of its arguments. (With b0da939346d3e3c16291bcff8723f2fcc63a966d, the call to the underlying function will obey's R's lazy eval behavior, assuming no cache, but the memoising procedure will still force the arguments, which could be problematic if an argument has reference semantics.)
- Your function might be generally pure, but not always. (This is how I'd interpret the gist of @chochkov's use case.)
In case 1, you'd also be spared the (typically low) overhead of memoisation. In case 2, a (contrived) example would be a functionfoo(x, update)
which is pure when update
is FALSE
, but impure when udpate
is TRUE
—say, it grabs data from some URL whose contents are time-dependent.
Moreover, including unmemoise()
as part of the package would bring such (albeit infrequent) use cases to the user's attention.
Would any of this warrant the creation of unmemoise()
?
Hope you don't mind the outside comment, but isn't this possible by using a file system cache, or by just saving the specific memory cache (environment) as a variable and then using that when memoizing?
You can just rm
the memoized function to get unmemoized behavior, and then re-memoize with the same cache to get the memoized behavior back, with all previously cached results. This could be repeated as needed. Can't memoize a function to the same name that it was defined as in the same environment where it was defined, but that seems like a bad idea anyway.
sum.cache <- cache_memory()
is.memoised(sum)
#> [1] FALSE
sum <- memoize(sum, cache= sum.cache)
is.memoised(sum)
#> [1] TRUE
has_cache(sum)( 1, 2, 3 )
#> [1] FALSE
sum( 1, 2, 3 )
#> [1] 6
has_cache(sum)( 1, 2, 3 )
#> [1] TRUE
rm(sum)
is.memoised(sum)
#> [1] FALSE
sum <- memoize(sum, cache= sum.cache)
has_cache(sum)( 1, 2, 3 )
#> [1] TRUE
@jefferys I see your point, but that procedure won't work in general, unfortunately. You have removed the binding named sum
from the global environment, but sum
remains in scope from the base environment.
I guess I don't understand what you mean. If the function to be memoised was not defined in the current scope/envionment, the memoised version hides it; the original was never changed by memoise()
. Removing the binding restores the previous, unmemoised situation. Are you are talking about being able to unmemoise a memoised function that is handed to you from another scope, e.g. a package? I don't think that is something you should need to do, or should do. It is part of the implementation. What if two functions are implemented to call each other, but don't form an infinite loop based on checking for a memoised value for the other?
If the function to be memoised was defined in the current scope, replacing it with a redefinition of the same name seems like a bad idea. Why not just use a different name? But even if you do yo can get the original back using @jimhester's insider trick of myFun <- environment(myFun)$`_f`
instead of `rm(myFun)`
There is also an environment(myFun)$`_cache`
that appears to allow you to grab the memoise cache even if you didn't save it before you memoised, e.g. by using sum.cache <- environment(myFun)$`_cache`
and then using cache= sum.cache
as a parameter when you memoise sum
again. It even seems to be smart enough to track the function name internally, e.g. c <- memoise( c, cache= sum.cache )
works fine, and doesn't seem to break the memoised sum
behavior either. Although this may have been changed only recently (#38)?
@jefferys In your example, you reassign sum
to memoised-sum
, then remove it, then rememoise. What I meant is that if you carried out that procedure for a user-defined function in place of sum
, it wouldn't work (the function wouldn't be found, and might even be garbage-collected, if there are no other references to it).
Getting the underlying function by directly accessing the environment of the memoised function works, of course, but it is not ideal because: 1) it's not declarative (of intent); 2) it depends on a detail of the current implementation of memoise()
. (Prior to the current devel version, the non-syntactic name `_f`
was used to minimize name clashes. That is no longer necessary, so it is conceivable that the binding to the underlying function would change in a future version.)