Я не уверен, насколько это "элегантно", но вот моя лучшая попытка удовлетворить требования ОП.Логика if / else на самом деле довольно проста (не требует вложенности, как таковой).Реальная работа заключается в сборе и дезинфекции трех различных типов ввода (формальные значения по умолчанию, объект списка и любые предоставленные аргументы).
fn <- function(a_list = NULL, x = 2, y = 3, z = 5, ...) {
formal_args <- formals() # get the function's defined inputs and defaults
formal_args[names(formal_args) %in% c('a_list', '...')] <- NULL # remove these two from formals
supplied_args <- as.list(match.call())[-1] # get the supplied arguments
supplied_args['a_list'] <- NULL # ...but remove the argument list
# for each uniquely named item among the 3 inputs (argument list, defaults, and supplied args):
for (i in unique(c(names(a_list), names(formal_args), names(supplied_args)))) {
if (!is.null(supplied_args[[i]])) {
assign(i, supplied_args[[i]])
} else if (!is.null(a_list[[i]])) {
assign(i, a_list[[i]])
}
}
print(c(x, y, z))
}
arg_lst <- list(x = 0, y = 1)
fn(a_list = arg_lst, y=7)
[1] 0 7 5
Немного больше углубляясь в функции метапрограммирования R, на самом деле этоМожно упаковать это иерархическое назначение в свою собственную функцию, которая предназначена для работы в функциональной среде, которая его вызывает.Это облегчает повторное использование этой функции, но она определенно нарушает область видимости и должна рассматриваться как опасная.
Функция «иерархического назначения», в основном такая же, как и раньше:
hierarchical_assign <- function(a_list) {
formal_args <- formals(sys.function(-1)) # get the function's defined inputs and defaults
formal_args[names(formal_args) %in% c('a_list', '...')] <- NULL # remove these two from formals
supplied_args <- as.list(match.call(sys.function(-1), sys.call(-1)))[-1] # get the supplied arguments
supplied_args['a_list'] <- NULL # ...but remove the argument list
# for each uniquely named item among the 3 inputs (argument list, defaults, and supplied args):
for (i in unique(c(names(a_list), names(formal_args), names(supplied_args)))) {
if (!is.null(supplied_args[[i]])) {
assign(i, supplied_args[[i]], envir = parent.frame())
} else if (!is.null(a_list[[i]])) {
assign(i, a_list[[i]], envir = parent.frame())
}
}
}
Ииспользование.Обратите внимание, что вызывающая функция должна иметь аргумент с именем a_list
, и он должен быть передан hierarchical_assign
.
fn <- function(a_list = NULL, x = 2, y = 3, z = 5, ...) {
hierarchical_assign(a_list)
print(c(x, y, z))
}
[1] 0 7 5