我尚未对此进行彻底测试,但它似乎适用于您的简单示例。这里我们定义reap
和sow
reap <- function(...) {
expr <- substitute(...)
REAPENV <- new.env()
parent.env(REAPENV) <- parent.frame()
x <- eval(expr, REAPENV)
c(list(x), as.list(REAPENV))
}
sow <- function(...) {
expr <- substitute(alist(...))[-1]
for( f in rev(sys.frames())) {
if(exists("REAPENV", envir=f)) {
re <- get("REAPENV", envir=f)
if (is.null(names(expr))) {
names(expr) <- if(length(expr)==1) {"sow"} else {letters[1:length(expr)]}
}
stopifnot(all(nchar(names(expr))!=0))
for(n in names(expr)) {
sx <- eval(expr[[n]], parent.frame())
cv <- if(exists(n, envir=re, inherits=FALSE)) {get(n, envir=re)} else {list()}
if(length(cv)>0) {
assign(n, append(cv, sx), envir=re)
} else {
assign(n, sx, envir=re)
}
}
break;
}
}
invisible(NULL)
}
所以该reap()
函数基本上只是定义了一个新环境并在该上下文中调用它的参数。该sow
函数采用一个命名参数列表,并评估它的参数并分配给最近的封闭“reap”环境。最后,reap()
将返回一个列表,其中包含作为第一个元素传递的表达式的“自然”返回值,然后它将添加与sow()
调用期间使用的名称相对应的命名元素。所以如果你跑
reap(sum(sapply(1:5, function(i) { sow(squares=i * i); i * i * i; })))
你得到
[[1]]
[1] 225
$squares
[1] 1 4 9 16 25
正如我所提到的,这似乎适用于简单的测试用例。我确信可以改进查找和分配到正确的工作收割环境。但这至少可以提供一个起点,如果您希望追求这样的事情。