これを完全にテストしたわけではありませんが、単純な例ではうまくいくようです。ここで定義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
前述したように、これは単純なテスト ケースで機能するようです。正しい作業リーピング環境を見つけて割り当てるには、改善を加えることができると確信しています。しかし、少なくともこのようなことを追求したい場合は、これが出発点になるかもしれません。