Great question.
Why your code fails
Your code fails because eval()'s
supplied enclos=
argument does not point far enough up the call stack to reach the environment in which you are wanting it to next search for unresolved symbols.
Here is a partial diagram of the call stack from the bottom of which your call to parent.frame()
occurs. (To make sense of this, it's important to keep in mind that the function call from which parent.frame()
is here being called is not f()
, but a call the anonymous function returned by f()
(let's call it fval
)).
## Note: E.F. = "Evaluation Frame"
## fval = anonymous function returned as value of nested call to f()
f( <------------------------- ## E.F. you want, ptd to by parent.frame(n=3)
Map(
mapply( <-------------------- ## E.F. pointed to by parent.frame(n=1)
fval( |
parent.frame(n=1 |
In this particular case, redefining the function returned by f()
to call parent.frame(n=3)
rather than parent.frame(n=1)
produces working code, but that's not a good general solution. For instance, if you wanted to call f(x = mapply(f(y = x + y), 1:2))(10)
, the call stack would then be one step shorter, and you'd instead need parent.frame(n=2)
.
Why flodel's code works
flodel's code provides a more robust solution by calling parent.frame()
during evaluation of the inner call to f
in the nested chain f(Map(f(), ...))
(rather than during the subsequent evaluation of the anonymous function fval
returned by f()
).
To understand why his parent.frame(n=1)
points to the appropriate environment, it's important to recall that in R, supplied arguments are evaluated in the the evaluation frame of the calling function. In the OP's example of nested code, the inner f()
is evaluated during the processing of Map()
's supplied arguments, so it's evaluation environment is that of the function calling Map()
. Here, the function calling Map()
is the outer call to f()
, and its evaluation frame is exactly where you want eval()
to next be looking for symbols:
f( <--------------------- ## Evaluation frame of the nested call to f()
Map(f( |
parent.frame(n=1 |