nЯ хотел бы использовать memoization для кэширования результатов некоторых дорогостоящих операций, чтобы они не вычислялись и снова.
Как memoise, так и R.cache подходит для моих нужд. Однако я обнаружил, что кэширование не является надежным для вызовов.
Вот пример, демонстрирующий проблему, которую я вижу:
library(memoise)
# Memoisation works: b() is called only once
a <- function(x) runif(1)
replicate(5, a())
b <- memoise(a)
replicate(5, b())
# Memoisation fails: mfn() is called every single time
ProtoTester <- proto(
calc = function(.) {
fn <- function() print(runif(1))
mfn <- memoise(fn)
invisible(mfn())
}
)
replicate(5, ProtoTester$calc())
Обновлено на основе ответа
На этот вопрос могут быть разные ответы в зависимости от того, используется ли постоянное или непостоянное кэширование. Для непостоянного кэширования (например, memoise
) может потребоваться однократное назначение, и тогда приведенный ниже ответ является хорошим способом. Постоянное кэширование (такое как R.cache
) работает между сеансами и должно быть устойчивым к нескольким назначениям. Описанный выше подход работает с R.cache
. Несмотря на несколько назначений, fn
вызывается только один раз с R.cache
. Он будет вызываться дважды с memoise
.
> ProtoTester <- proto(
+ calc = function(.) {
+ fn <- function() print(runif(1))
+ invisible(memoizedCall(fn))
+ }
+ )
> replicate(5, ProtoTester$calc())
[1] 0.977563
[1] 0.1279641
[1] 0.01358866
[1] 0.9993092
[1] 0.3114813
[1] 0.97756303 0.12796408 0.01358866 0.99930922 0.31148128
> ProtoTester <- proto(
+ calc = function(.) {
+ fn <- function() print(runif(1))
+ invisible(memoizedCall(fn))
+ }
+ )
> replicate(5, ProtoTester$calc())
[1] 0.97756303 0.12796408 0.01358866 0.99930922 0.31148128
Причина, по которой я думал, что у меня проблема с R.cache
, заключается в том, что я передал метод proto
в качестве функции memoizedCall
. Методы proto
привязаны к средам таким образом, что R.cache
с ними трудно. Что вам нужно сделать в этом случае, так это отменить привязку функции (перейти от созданного метода к простой функции), а затем передать объект вручную в качестве первого аргумента. В следующем примере показано, как это работает (и Report
, и Report$loader
являются объектами proto
:
# This will not memoize the call
memoizedCall(Report$loader$download_report)
# This works as intended
memoizedCall(with(Report$loader, download_report), Report$loader)
Я хотел бы знать, почему R.cache
работает с обычными функциями, привязанными к средам, но не работает с proto
экземплярами методов.