Передача отсутствующего аргумента от функции к функции в R

Я узнал, что обычной практикой является использование необязательных аргументов в функции и проверка их с помощью missing () (например, как обсуждалось в SO 22024082)

В этом примере round0 является необязательным аргументом (я знаю, round0 может быть определен как логический).

foo = function(a, round0) {
    a = a * pi
    if(!missing(round0)) round(a)
    else a
}

Но что, если я вызываю эту функцию из другой функции, как я могу передать слово "отсутствует"?

bar = function(b) {
    if(b > 10) round1=T
    foo(b, round1)
}

Если b < 10, то round1 в bar () не определен, но все равно передается в foo. Если я изменю foo ():

foo = function(a, round0) {
    a = a * pi
    print(missing(round0))
    print(round0)
    if(!missing(round0)) round(a)
    else a
}

и запустите бар (9):

bar(9)
[1] FALSE
Error in print(round0) : object 'round1' not found
Called from: print(round0)

Это означает, что round0 не пропущен, но также недоступен?

Я не хочу использовать разные вызовы функций в bar (), если в foo () есть несколько необязательных аргументов, мне придется написать вызов функции для каждого отсутствующего / не пропущенного - комбинации всех необязательных аргументов.

Можно ли пропустить "отсутствует", или какое другое решение подойдет для этой проблемы?

2 ответа

Решение

В вашем примере round0 не пропущен, он установлен в round1 который не определен (в отличие от отсутствия).

В общем, лучший способ сделать это - использовать значение по умолчанию, в вашем случае FALSE:

foo = function(a, round0 = FALSE) {
    a = a * pi
    if (!round0) round(a)
    else a
}

bar = function(b) {
    round1 <- FALSE
    if (b > 10) round1=TRUE
    foo(b, round1)
}

или где значение по умолчанию не может быть легко выражено в списке параметров:

foo = function(a, round0 = NULL) {
    a = a * pi
    if(!is.null(round0)) round(a)
    else a
}

bar = function(b) {
    round1 <- NULL
    if (b > 10) round1=TRUE
    foo(b, round1)
}

Обратите внимание, что в обоих случаях вам нужно вручную установить параметр в качестве значения по умолчанию в вызывающей функции.

Вы также можете позвонить foo функция с или без аргумента, если это необходимо в вашем if заявление:

bar = function(b) {
    if (b > 10) foo(b, TRUE) else foo(b)
}

Но вы не можете (насколько я знаю) сделать переменную missing кроме просто не передавая это в качестве аргумента.

Недавно я столкнулся с подобной проблемой и хотел решить ее в общем виде. Я думаю, что это можно сделать, как показано в определении функции g() ниже:

f <- function(a = 5, b = 3, c = 2, d = 7) {
  if (missing(a)) {print("a is missing.")}
  if (missing(b)) {print("b is missing.")}
  if (missing(c)) {print("c is missing.")}
  if (missing(d)) {print("d is missing.")}

  cat(a, b, c, d)
}

g <- function(a = 1, b = 1, c = 1, d = 1) {
  args <- as.list(match.call())
  args[[1]] <- NULL # remove first list element, it's the function call
  do.call(f, args, envir = parent.frame())
}

Вот что мы получаем при звонке g() с разными наборами аргументов:

> g()
[1] "a is missing."
[1] "b is missing."
[1] "c is missing."
[1] "d is missing."
5 3 2 7

> g(a = 3)
[1] "b is missing."
[1] "c is missing."
[1] "d is missing."
3 3 2 7

> g(b = 10, c = 10)
[1] "a is missing."
[1] "d is missing."
5 10 10 7

Вы можете добавить или удалить из args список, если вы не хотите передавать все аргументы следующей функции или хотите добавить некоторые. В качестве примера см. Следующую функцию g() это делает это в общем виде:

g <- function(a = 1, b = 1, c = 1, x = 1, y = 1, z = 1) {
  f_args <- c("a", "b", "c") # arguments we want to hand off to function f

  # obtain the list of arguments provided
  args <- as.list(match.call())
  # remove first list element, it's the function call
  args[[1]] <- NULL
  # remove the arguments that are not listed in f_args
  args <- args[na.omit(match(f_args, names(args)))]

  # now add argument d, we always want it to be 0:
  args <- c(args, list(d = 0))
  do.call(f, args, envir = parent.frame())
}

Вот что мы получаем при звонке g() с разными наборами аргументов:

> g()
[1] "a is missing."
[1] "b is missing."
[1] "c is missing."
5 3 2 0

> g(a = 3)
[1] "b is missing."
[1] "c is missing."
3 3 2 0

> g(b = 10, c = 10)
[1] "a is missing."
5 10 10 0

Смотрите этот ответ для получения дополнительной информации о do.call(),

Вы можете создать недостающий объект, используя substitute() без аргументов.

В вашем случае мы могли бы сделать round1 отсутствующий объект в else пункт:

foo = function(a, round0) {
  a = a * pi
  if(!missing(round0)) round(a)
  else a
}

bar = function(b) {
  if(b > 10) round1=T else round1 <- substitute()
  foo(b, round1)
}

bar(9)
#> [1] 28.27433

Создано 24.10.2019 пакетом REPEX (v0.3.0)

rlang предоставляет также функцию missing_arg() это делает аргумент отсутствующим.

foo = function(a, round0) {
  a = a * pi
  if(!missing(round0)) round(a)
  else a
}

bar = function(b) {
  if(b > 10) round1 <- TRUE else round1 <- rlang::missing_arg()
  foo(b, round1)
}

foo(9)
#> [1] 28.27433
bar(9)
#> [1] 28.27433

Создано 02.12.2020 пакетом REPEX (v0.3.0)

Другие вопросы по тегам