Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unmemoise function? #36

Open
chochkov opened this issue Mar 29, 2017 · 6 comments
Open

unmemoise function? #36

chochkov opened this issue Mar 29, 2017 · 6 comments
Labels
feature a feature request or enhancement

Comments

@chochkov
Copy link

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?

@jimhester
Copy link
Member

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?

@egnha
Copy link
Contributor

egnha commented May 5, 2017

@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)?:

  1. You want a specific call to adhere to lazy evaluation of its arguments. (With b0da939, 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.)
  2. 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()?

@jefferys
Copy link

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

@egnha
Copy link
Contributor

egnha commented May 15, 2017

@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.

@jefferys
Copy link

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)?

@egnha
Copy link
Contributor

egnha commented May 15, 2017

@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.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature a feature request or enhancement
Projects
None yet
Development

No branches or pull requests

4 participants