简体   繁体   English

全局环境中的递归eval

[英]Recursive eval in the global environment

I am having a hard time understanding why my attempt to recursively apply eval , using rapply , is not working. 我很难理解为什么我使用rapply以递归方式应用eval尝试不起作用。

I have a nested list of expressions: 我有一个嵌套的表达式列表:

# Some expressions   
expr1 <- quote(x <- x + 9)
expr2 <- quote(x <- x/2)
expr3 <- quote(x <- x + 3)
expr4 <- quote(x <- x * 3)

# Generate a nested list of expressions
exprs <- list(expr1, list(expr2, expr3), expr4)

# Initialize x, and attempt to eval the expressions
x <- 1
rapply(exprs, eval, envir = globalenv())
# Returns: [1] 10  5  8 24, but x is not changed.

Clearly the recursion worked, but it did not evaluate the expression in the global environment, like I specified. 很明显,递归有效,但它没有像我指定的那样评估全局环境中的表达式。 Based on this answer I flattened out the list, and can eval using lapply . 基于这个答案我夷为平地的列表,并且可以eval使用lapply

flatten <- function(x) {
  repeat {
    if(!any(vapply(x, is.list, logical(1)))) return(x)
    x <- Reduce(c, x)
  }
}

# Both change x to 24 in the global env, like desired.
lapply(flatten(exprs), eval, envir = globalenv())
lapply(flatten(exprs), eval, envir = parent.frame())

As far as I understand rapply / lapply evaluate in their own environment, just like any other function, then return a value. 据我所知, rapply / lapply在自己的环境中进行评估,就像任何其他函数一样,然后返回一个值。 It makes sense that I can specify the global environment, or the parent frame (because the parent frame of lapply should be the environment it was called in - here the global environment.) 有意义的是,我可以指定全局环境或父框架(因为lapply的父框架应该是它所调用的环境 - 这里是全局环境。)

Following this logic I would expect specifying the global environment with rapply to work. 按照这个逻辑,我希望用rapply指定全局环境。 Specifying the parent frame should fail (and it does), because I am assuming the calls nested one deep within rapply get evaluated in the environment created by the original call to rapply . 指定父框架应该失败(并且确实如此),因为我假设嵌套在rapply一个深度调用在由原始调用rapply创建的环境中进行评估。

What am I missing here? 我在这里错过了什么? Why doesn't the rapply call change x in the global environment? 为什么rapply调用不会在全球环境中改变x

Note from documentation for rapply : rapply文档中的注意事项:

The semantics differ in detail from lapply: in particular the arguments are evaluated before calling the C code . 语义与lapply的细节不同:特别是在调用C代码之前评估参数

Try the following to see what they mean: 请尝试以下方法来查看它们的含义:

rapply(list(quote(stop("error"))), function(x) x)
# Error in (function (x)  : error
lapply(list(quote(stop("error"))), function(x) x)
# [[1]]
# stop("error")

You can try this as a workaround: 你可以尝试这个解决方法:

rapply(exprs, evalq, envir = globalenv())  # updated with Hadley's equivalent but cleaner version.
# [1] 10  5  8 24
x
# [1] 24

As you noted, x is getting evaluated in the rapply environment, which is why the result makes sense, but the actual eval statement is not of your original expression, but of the result (ie in the first iteration, 10 gets evaluated in the global env, not x <- x + 9 ). 正如您所指出的, x正在rapply环境中进行评估,这就是结果有意义的原因,但实际的eval语句不是原始表达式,而是结果(即在第一次迭代中, 10在全局中进行评估) env,而不是x <- x + 9 )。 By using substitute we're able to salvage the original expression. 通过使用substitute我们能够挽救原始表达。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM