Необходимо проверить функцию мемоизированного пакета, чтобы мемоизация работала

Допустим, у меня есть пакет со следующей функцией:

foo <- function() {
  Sys.sleep(1) # really expensive operation
  return(1)
}

Значение функции всегда одно и то же для каждого прогона, поэтому я хотел бы использовать мемоизацию.

Я думал, что могу просто сделать

foo <- memoise::memoise(function() {
  Sys.sleep(1) # really expensive operation
  return(1)
})

Однако это не работает.

Я имею в виду, если запустить его как функцию GlobalEnv, он работает:

foo <- memoise::memoise(function() {
  Sys.sleep(1)
  return(1)
})

system.time(foo())
#>    user  system elapsed 
#>       0       0       1

system.time(foo())
#>    user  system elapsed 
#>    0.01    0.00    0.01

Создано 23.12.2019 пакетом REPEX (v0.3.0)

Однако, если он находится в пакете, я получаю действительно странное поведение. В общем, запоминание не срабатывает, и я продолжаю получать ту же цену. Однако, если я распечатаю определение функции, оно начнет работать!

system.time(bar::foo())
#>    user  system elapsed 
#>    0.47    0.08    2.55

system.time(bar::foo())
#>    user  system elapsed 
#>       0       0       2

system.time(bar::foo())
#>    user  system elapsed 
#>    0.02    0.00    2.02

system.time(bar::foo())
#>    user  system elapsed 
#>    0.01    0.00    2.02

bar::foo
#> Memoised Function:
#> function() {
#>   Sys.sleep(2)
#>   return (1)
#> }
#> <environment: namespace:bar>

system.time(bar::foo())
#>    user  system elapsed 
#>       0       0       2

system.time(bar::foo())
#>    user  system elapsed 
#>       0       0       0

system.time(bar::foo())
#>    user  system elapsed 
#>       0       0       0

system.time(bar::foo())
#>    user  system elapsed 
#>       0       0       0

Для протокола, вот соответствующие части NAMESPACE а также DESCRIPTION файлы:

# NAMESPACE
export(foo)
importFrom(memoise,memoise)

# DESCRIPTION [...]
Imports:
    memoise

Что здесь происходит и что мне делать, чтобы мемоизация работала с самого начала в моем пакете?

1 ответ

Похоже на ошибку в memoiseпакет. Когда вы работаете над своим собственным пакетом, R может добавлять отладочную информацию (называемуюsrcrefs) к функциям. Что-то в этом приводит к тому, что хэш выводится по-разному каждый раз, когда вы вызываете функцию, поэтому он никогда не распознает, что вы вызываете с одними и теми же аргументами.

Простым обходным решением является удаление параметра установки "--with-keep.source" при установке собственного пакета. (Если вы используете RStudio, это добавляется автоматически вProject Options | Build Tools | Install and Restart....) Это остановит R от добавления srcref, и ошибка в memoiseне сработает. К сожалению, это наносит вред отладчику в RStudio и других интерфейсах, поэтому он не идеален.

Другой обходной путь, который не мешает работе отладчика (за исключением этой функции), - использовать removeSourceна цель, которая запоминается. Например,

foo <- memoise::memoise(removeSource(function() {
  Sys.sleep(1) # really expensive operation
  return(1)
}))
Другие вопросы по тегам