Есть ли способ предотвратить ошибку promise already under evaluation
, когда
- вы хотите, чтобы имя аргумента функции было именем существующей функции
- и вы хотите установить значение по умолчанию для этого конкретного аргумента
- и вы хотите иметь возможность вызывать внешнюю функцию только с ее значениями по умолчанию (т.е. без необходимости передавать явное значение каждому аргументу)?
В моем примере ниже, пока foo(1:5, bar)
работает, foo(1:5)
выдает такую ошибку.
Конечно, я мог бы пойти и изменить имя аргумента с bar
, скажем, на bar_fun
, но я бы предпочел придерживаться фактического имени функции, если это возможно.
foo <- function(x, bar = bar) {
bar(x)
}
bar <- function(x) {
UseMethod("bar")
}
bar.default <- function(x) {
sum(x)
}
foo(1:5)
#> Error in foo(1:5): promise already under evaluation: recursive default argument reference or earlier problems?
foo(1:5, bar)
#> [1] 15
Мотивация (первый заказ)
В реальных условиях использования bar()
на самом деле settings()
, функция, которая возвращает список настроек. Я хотел бы изменить эти настройки. Так будет, например, такие методы, как settings.v1
, settings.v2
, ... и settings.default
.
И я подумал об использовании settings.default
для определения «используемой версии» используемых настроек, например ::
settings <- function(x) {
UseMethod("settings")
}
settings.v1 <- function(x) {
list(system = "dev")
}
settings.v2 <- function(x) {
list(system = "production")
}
settings.default <- function(x) {
settings.v2(
}
foo <- function(x, settings = settings) {
settings()
}
foo()
#> Error in foo(): promise already under evaluation: recursive default argument reference or earlier problems?
foo(settings = settings)
#> $system
#> [1] "production"
Поскольку settings.default()
вызывает метод настроек, который я хочу использовать, было бы замечательно, если бы я мог просто вызвать foo()
с его настройками по умолчанию (который затем всегда выбирал бы метод settings.default()
).
Мотивация (второй заказ)
Я экспериментирую с более строгим соблюдением принципов функционального программирования (см., Например, главу из Advanced R или ссылка на википедию ) и ее различие pure и эффективных / побочных эффектов функций.
Раньше я, вероятно, реализовывал бы настройки через какую-то глобальную переменную 1054 *, к которой, таким образом, каждый foo()
имел доступ, поэтому я мог быть ленивым и не определять его как аргумент функции foo()
, но foo()
тогда будет зависеть от вещей за пределами его области видимости - что очень плохо для FP.
Теперь я хочу по крайней мере заявить о зависимости foo()
от моих настроек, передав ей функцию, которая возвращает значения настроек - что является своего рода ленивостью, по крайней мере, в какой-то степени отвечающей принципам FP верхнего уровня.
Конечно, не ленивое (и, возможно, лучшее) решение состояло бы в том, чтобы аккуратно указывать все фактические зависимости настроек один за другим в качестве аргументов функции в foo()
, например. foo(settings_system = settings()$system)
; -)