Когда использовать пропущенные значения против NULL для передачи неопределенных аргументов функции в R и почему?

На сегодняшний день при написании функций R я передал неопределенные аргументы как значения NULL, а затем проверил, являются ли они NULL, т.е.

f1 <- function (x = NULL) {
   if(is.null(x))
      ...
}

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

f2 <- function (x) {
   if(missing(x))
      ...
}

В документации R говорится, что

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

Понятно, что это один из недостатков использования пропущенных для определения неопределенных значений. Есть ли другие люди или кто-то знает? Или сформулировать вопрос в более полезной форме: "Когда вы используете пропущенные значения против NULL для передачи неопределенных аргументов функции в R и почему?"

2 ответа

Решение

missing(x) кажется, немного быстрее, чем использовать по умолчанию аргумент x равно NULL,

> require('microbenchmark')
> f1 <- function(x=NULL) is.null(x)
> f2 <- function(x) missing(x)

> microbenchmark(f1(1), f2(1))
Unit: nanoseconds
  expr min  lq median    uq  max neval
 f1(1) 615 631  647.5 800.5 3024   100
 f2(1) 497 511  567.0 755.5 7916   100

> microbenchmark(f1(), f2())
Unit: nanoseconds
 expr min  lq median    uq  max neval
 f1() 589 619    627 745.5 3561   100
 f2() 437 448    463 479.0 2869   100

Обратите внимание, что в f1 дело x по-прежнему считается пропавшим без вести, если вы звоните f1(), но имеет значение, которое может быть прочитано в f1,

Второй случай более общий, чем первый. missing() просто означает, что пользователь не передал никакого значения. is.null()NULL default arg) утверждает, что пользователь либо ничего не пропустил, либо пропустил NULL,

Кстати, plot.default() а также chisq.test() использование NULL для их вторых аргументов. С другой стороны, getS3method('t.test', 'default') использования NULL за y аргумент и missing() за mu (чтобы быть готовым ко многим сценариям использования).

Я думаю, что некоторые пользователи R предпочтут f1функции, особенно при работе с *apply семья:

sapply(list(1, NULL, 2, NULL), f1)

Достижение этого в f2 дело не так просто.

NULL это просто другое значение, которое вы можете присвоить переменной. Он ничем не отличается от любого другого значения по умолчанию, которое вы назначаете в объявлении вашей функции.

missing с другой стороны, проверяет, предоставил ли пользователь этот аргумент, что вы можете сделать до назначения по умолчанию - что благодаря ленивой оценке R происходит только при использовании этой переменной.

Вот несколько примеров того, чего вы можете достичь: аргументы без значения по умолчанию, которые вы все равно можете опустить - например, file а также text в read.tableили аргументы со значениями по умолчанию, где вы можете указать только один - например, n а также nmax в scan,

Вы найдете много других вариантов использования, просматривая код R.

На мой взгляд, непонятно, когда ограничение на missingприменяется. В документации, как вы цитируете, говорится, что значение missing можно использовать только в самом теле функции. Однако простой пример показывает, что это не так и что все работает должным образом, когда аргументы передаются вложенной функции.

f1 = function(x, y, z){
  if(!missing(x))
    print(x)
  if(!missing(y))
    print(y)
}

f2 = function(x, y, z){
  if(!missing(z)) print(z)
  f1(x, y)
}
f1(y="2")
#> [1] "2"
f2(y="2", z="3")
#> [1] "3"
#> [1] "2"
f2(x="1", z="3")
#> [1] "3"
#> [1] "1"

Хотелось бы увидеть пример, когда missing не работает во вложенной функции.

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

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