I am aware of the other answers on substitute
, quote
, and eval
(e.g.,
this
answer).
However, I am still confused about the following scenario. I will err on the
site of verbosity for the steps below to ensure what I am trying to do is
clear.
Suppose I have four functions (i.e., see below) that all take an expression
, pass it around, and only the root one evaluates it.
f1 <- function(expr) {
x <- "Hello!"
do.call(eval, list(expr = expr))
}
f2 <- function(expr) {
f1(expr)
}
f3 <- function(expr) {
f2(expr)
}
f4 <- function(expr) {
f3(expr)
}
Then, I am interested in passing an unquoted expression to any of f2
,
f3
, or f4
that should not be evaluated right away. More specifically, I
would like to call:
f4(print(paste0("f4: ", x)))
f3(print(paste0("f3: ", x)))
f2(print(paste0("f2: ", x)))
and observe the following output:
[1] "f4: Hello!"
[1] "f3: Hello!"
[1] "f2: Hello!"
However, calling, e.g., f4(print(paste0("f4: ", x)))
, right now will result in
an error that x
is not defined, which is, indeed, not defined until the environment of f1
:
Error in paste0("x: ", x) : object 'x' not found
I can use substitute
in f4
to get the parse tree of the expression, e.g.:
f4 <- function(expr) {
f3(substitute(expr))
}
then call the function
f4(print(paste0("f4: ", x)))
and obtain:
[1] "f4: Hello!"
[1] "f4: Hello!"
The double output is probably because the argument of eval
, i.e., expr
in f1
, is unquoted. Quoting it solves this early evaluation:
f1 <- function(expr) {
x <- "Hello!"
do.call(eval, list(expr = quote(expr)))
}
f4(print(paste0("f4: ", x)))
# [1] "f4: Hello!"
If I apply the same logic to, say, f3
, e.g.:
f3 <- function(expr) {
f2(substitute(expr))
}
calling f3
works as expected, i.e.:
f3(print(paste0("f3: ", x)))
# [1] "f3: Hello!"
but now calling f4
fails, with the output being expr
.
f4(print(paste0("f4: ", x)))
At this point, I am not exactly sure how or if this is even possible to achieve.
Of course, the simplest way would be to just pass a quoted expression to any of these functions. However, I am curious how to achieve this without quote
.