Non standard evaluation from another function in R

后端 未结 3 1151
梦毁少年i
梦毁少年i 2021-02-02 12:38

Here is an example from Hadley\'s advanced R book:

sample_df <- data.frame(a = 1:5, b = 5:1, c = c(5, 3, 1, 4, 1))

subset2 <- function(x, condition) {
  c         


        
3条回答
  •  野趣味
    野趣味 (楼主)
    2021-02-02 13:16

    This was a tricky one, so thanks for the question. The error has to do with how substitute acts when it's called on an argument. If we look at the help text from substitute():

    Substitution takes place by examining each component of the parse tree as follows: If it is not a bound symbol in env, it is unchanged. If it is a promise object, i.e., a formal argument to a function or explicitly created using delayedAssign(), the expression slot of the promise replaces the symbol.

    What this means is that when you evaluate condition within the nested subset2 function, substitute sets condition_call to be the promise object of the unevaluated 'condition' argument. Since promise objects are pretty obscure, the definition is here: http://cran.r-project.org/doc/manuals/r-release/R-lang.html#Promise-objects

    The key points from there are:

    Promise objects are part of R’s lazy evaluation mechanism. They contain three slots: a value, an expression, and an environment.

    and

    When the argument is accessed, the stored expression is evaluated in the stored environment, and the result is returned

    Basically, within the nested function, condition_call is set to the promise object condition, rather than the substitution of the actual expression contained within condition. Because promise objects 'remember' the environment they come from, it seems this overrides the behavior of eval() - so regardless of the second argument to eval(), condition_call is evaluated within the parent environment that the argument was passed from, in which there is no 'a'.

    You can create promise objects with delayedAssign() and observe this directly:

    delayedAssign("condition", a >= 4)
    substitute(condition)
    eval(substitute(condition), sample_df)
    

    You can see that substitute(condition) does not return a >= 4, but simply condition, and that trying to evaluate it within the environment of sample_df fails as it does in Hadley's example.

    Hopefully this is helpful, and I'm sure someone else can clarify further.

提交回复
热议问题