Rで関数を実行すると、その中で別の関数が実行されます。この行にコードがあります:
f_a <- function(b, c){
return(b + c)
}
f_e <- function(){
b = 2
c = 2
d = f_a(b, c)
print(d)
}
これは正常に動作します。私がしたいのは変数を渡さないb, c
を関数f_a
に渡すことです。私はこのようなことをしたいと思います(エラーをスローします)
f_a <- function(){
return(b + c)
}
f_e <- function(){
b = 2
c = 2
d = f_a()
print(d)
}
環境や検索パスなどを使用してこれを行う方法はありますか?
字句スコープ についてお読みになることをお勧めしますが、多くの変数を記述しないようにするための適切なアプローチは次のとおりです。
get_args_for <- function(fun, env = parent.frame(), inherits = FALSE, ..., dots) {
potential <- names(formals(fun))
if ("..." %in% potential) {
if (missing(dots)) {
# return everything from parent frame
return(as.list(env))
}
else if (!is.list(dots)) {
stop("If provided, 'dots' should be a list.")
}
potential <- setdiff(potential, "...")
}
# get all formal arguments that can be found in parent frame
args <- mget(potential, env, ..., ifnotfound = list(NULL), inherits = inherits)
# remove not found
args <- args[sapply(args, Negate(is.null))]
# return found args and dots
c(args, dots)
}
f_a <- function(b, c = 0, ..., d = 1) {
b <- b + 1
c(b = b, c = c, d = d, ...)
}
f_e <- function() {
b <- 2
c <- 2
arg_list <- get_args_for(f_a, dots = list(5))
do.call(f_a, arg_list)
}
> f_e()
b c d
3 2 1 5
デフォルトでinherits = FALSE
を設定すると、指定した環境からのみ変数を取得できます。また、dots = NULL
を呼び出すときにget_args_for
を設定して、すべての変数を渡すのではなく、省略記号を空のままにすることもできます。
それにもかかわらず、dots
が末尾に追加されるだけであり、一部の引数に名前が付けられていない場合、それらは位置によって一致してしまう可能性があるため、完全に堅牢ではありません。また、呼び出しで一部の値がNULL
である必要がある場合、それを検出するのは簡単ではありません。
これらをRパッケージ内で使用しないことを強くお勧めします。見苦しいだけでなく、RのCMDチェックから未定義のグローバル変数に関する一連のメモが表示されます。
別のオプション。
f_a <- function() {
return(b + c)
}
f_e <- function() {
b <- 2
c <- 2
# replace f_a's enclosing environment with the current evaluation's environment
environment(f_a) <- environment()
d <- f_a()
d
}
> f_e()
[1] 4
上記のようなものはおそらくRパッケージの内部では機能しないでしょう。なぜなら、パッケージの関数はそれを囲む環境がロックされていると思うからです。
または:
f_a <- function() {
with(parent.frame(), {
b + c
})
}
f_e <- function() {
b <- 2
c <- 2
f_a()
}
> f_e()
[1] 4
そうすれば、他の関数を囲む環境を永続的に変更する必要がなくなります。ただし、両方の関数が環境を共有するため、次のようなことが起こります。
f_a <- function() {
with(parent.frame(), {
b <- b + 1
b + c
})
}
f_e <- function() {
b <- 2
c <- 2
d <- f_a()
c(b,d)
}
> f_e()
[1] 3 5
内部関数を呼び出すと、外部環境の値が変更されます。
もう1つのオプションは、eval
を使用して一時的に囲み環境を変更するだけなので、もう少し柔軟です。ただし、「daRk magic」を通じて現在の実行環境を検出する特定のR関数があり、eval
に騙されることはできません。 この説明 を参照してください。
f_a <- function() {
b <- b + 1
b + c
}
f_e <- function() {
b <- 2
c <- 2
# use current environment as enclosing environment for f_a's evaluation
d <- eval(body(f_a), list(), enclos=environment())
c(b=b, d=d)
}
> f_e()
b d
2 5
1つのオプションは、呼び出し環境からa
およびb
を明示的に取得することです。
f_a <- function(){
get('b', envir = parent.frame()) + get('c', envir = parent.frame())
}
f_e <- function(){
b = 2
c = 2
d = f_a()
d
}
f_e()
#> [1] 4
または、quote
を使用して評価を遅らせ、次にeval
を使用して呼び出し環境でコードを評価し、実質的に同じことを行うことができます。
f_a <- function(){
eval(quote(b + c), parent.frame())
}
ただし、これはf_a
を正常に呼び出すための可能な方法を制限するため、コードを記述するための堅牢な方法ではありません。変数を明示的に渡すコードを実行する方がはるかに簡単です。
編集:
@alistaireがquote
を使用して式を作成するという提案は、次の代替案を提示しますが、見た目はそれほど醜くありません。
expr_env <- new.env()
expr_env$f_a <- quote(b+c)
expr_env$f_z <- quote(x+y)
f_e<-function(){
b=2
c=2
d=eval( expr_env$f_a)
print(d)
}
local
を使用して関数を定義することは、受け入れ可能な代替手段ですか?
f_e<-function(){
b=2
c=2
d<-local({
b+c
})
print(d)
}
f_e()
[1] 4
別の方法は、解析ツリーのみを返し、関数の「ローカル」環境での評価を終了することです。これは私にとって「醜い」ようです:
expr_list<-function(){ f_a <- quote(b+c)
f_z <- quote(x+y)
list(f_a=f_a,f_z=f_z) }
f_e<-function(){
b=2
c=2
d=eval( (expr_list()$f_a))
print(d)
}
変数をグローバル環境に割り当てて、関数内で使用できます。
f_a <- function(){
return(b + c)
}
f_e <- function(){
assign("b", 2, envir = .GlobalEnv)
assign("c", 2, envir = .GlobalEnv)
d = f_a()
print(d)
}
# > f_e()
# [1] 4