Reputation: 13100
Is there a way to prevent a promise already under evaluation
error when
In my example below, while foo(1:5, bar)
works, foo(1:5)
throws such an error.
Of course I could go and change the argument name from bar
to, say, bar_fun
, but I would rather stick with the actual function's name if possible.
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
The real-world use case is that bar()
is actually settings()
, a function which returns a list of settings. I'd like to version those settings. So there'd be e.g. methods like settings.v1
, settings.v2
, ..., and settings.default
.
And I thought of using settings.default
to define the "runtime version" of settings to use, so e.g.:
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"
Since settings.default()
calls the settings method I want to use, it'd be great if I could just call foo()
with its defaults (which would then always pick up the settings.default()
method).
I'm experimenting with adhering more to principles of functional programming (see e.g. chapter from Advanced R or wikipedia link) and its distinction of pure and effectful/side-effecty functions.
Previously, I probably would have implemented settings via some sort of a global variable that thus each foo()
had access to, so I could be lazy and not define it as an argument of function foo()
, but foo()
then would depend on things outside of its scope - which is a very bad thing in FP.
Now I want to at least state the dependency of foo()
on my settings by handing it a function that returns the settings values - which is sort of my lazyness at least complying to some extend with top-level FP principles.
Of course the non-lazy (and arguably best) solution would be to carefully state all actual settings dependencies one by one as function arguments in foo()
, e.g. foo(settings_system = settings()$system)
;-)
Upvotes: 3
Views: 58
Reputation: 270448
1) Try explicitly getting it from the parent:
foo <- function(x, bar = get("bar", 1)) {
bar(x)
}
2) Another possibility is to use an argument name such as bar.
. The user can still write foo(1:15, bar = whatever)
, e.g. any of these three calls work:
foo <- function(x, bar. = bar) {
bar.(x)
}
foo(1:5)
foo(1:5, bar)
foo(1:5, bar = bar)
Upvotes: 3