sys.call()
を使用して、呼び出し側から与えられた関数引数にアクセスすることができます。 sys.call()
は引数を評価せず、代わりにという式を提供するので、注意が必要です。これは、関数が...
を引数として呼び出されたときに特に困難になります。sys.call()
には、その値ではなく...
が含まれます。ただし、sys.call()
をとり、別の関数の引数リストとして評価することもできます(例:list()
)。これはすべての約束を評価し、いくつかの情報を捨てますが、私はRの内部一致を回避しようとするときにこれを回避する方法を見ることができません。
1つのアイデアは、厳密な一致をシミュレートすることです。これが一致しない引数除外さ
:私は、まさにこの関数の最初のコマンドとして呼び出された場合ないヘルパー関数を追加
> fun(10, b = 20)
[[1]]
[1] 10
[[2]]
[1] ""
$b
[1] 20
をしてもして(他のほとんどのケースで動作するはずですか
...
なし、
...
の右側にある引数を引数の既定値としています)。それがうまく動作しないのは、非標準的な評価だけです。引数の式を
substitute(arg)
を使用して取得しようとしているとき。
ヘルパー機能
strictify <- function() {
# remove argument values from the function
# since matching already happened
parenv <- parent.frame() # environment of the calling function
rm(list=ls(parenv), envir=parenv) # clear that environment
# get the arguments
scall <- sys.call(-1) # 'call' of the calling function
callingfun <- scall[[1]]
scall[[1]] <- quote(`list`)
args <- eval.parent(scall, 2) # 'args' is now a list with all arguments
# if none of the argument are named, we need to set the
# names() of args explicitly
if (is.null(names(args))) {
names(args) <- rep("", length(args))
}
# get the function header ('formals') of the calling function
callfun.object <- eval.parent(callingfun, 2)
callfun.header <- formals(callfun.object)
# create a dummy function that just gives us a link to its environment.
# We will use this environment to access the parameter values. We
# are not using the parameter values directly, since the default
# parameter evaluation of R is pretty complicated.
# (Consider fun <- function(x=y, y=x) { x } -- fun(x=3) and
# fun(y=3) both return 3)
dummyfun <- call("function", callfun.header, quote(environment()))
dummyfun <- eval(dummyfun, envir=environment(callfun.object))
parnames <- names(callfun.header)
# Sort out the parameters that didn't match anything
argsplit <- split(args, names(args) %in% c("", parnames))
matching.args <- c(list(), argsplit$`TRUE`)
nonmatching.arg.names <- names(argsplit$`FALSE`)
# collect all arguments that match something (or are just
# positional) into 'parenv'. If this includes '...', it will
# be overwritten later.
source.env <- do.call(dummyfun, matching.args)
for (varname in ls(source.env, all.names=TRUE)) {
parenv[[varname]] <- source.env[[varname]]
}
if (!"..." %in% parnames) {
# Check if some parameters did not match. It is possible to get
# here if an argument only partially matches.
if (length(nonmatching.arg.names)) {
stop(sprintf("Nonmatching arguments: %s",
paste(nonmatching.arg.names, collapse=", ")))
}
} else {
# we manually collect all arguments that fall into '...'. This is
# not trivial. First we look how many arguments before the '...'
# were not matched by a named argument:
open.args <- setdiff(parnames, names(args))
taken.unnamed.args <- min(which(open.args == "...")) - 1
# We throw all parameters that are unmatched into the '...', but we
# remove the first `taken.unnamed.args` from this, since they go on
# filling the unmatched parameters before the '...'.
unmatched <- args[!names(args) %in% parnames]
unmatched[which(names(unmatched) == "")[seq_len(taken.unnamed.args)]] <- NULL
# we can just copy the '...' from a dummy environment that we create
# here.
dotsenv <- do.call(function(...) environment(), unmatched)
parenv[["..."]] <- dotsenv[["..."]]
}
}
また、例えば、厳密マッチング関数に通常一致する関数を変換する機能を有することが可能であろう
strict.fun = strictificate(fun)
でも、同じ種類のトリックを使用します。
おそらく 'sys.call()'を使用して、関数がどのように呼び出されたかを調べることができます。 –
新しいAPIの 'myFunc2'を呼び出し、古いもの(' myFunc')を下位互換性のためそのまま維持します(ただし、実装を 'myFunc2'の周りの単純なラッパーに変更します)? – NPE