R: Понимание того, как многоточие (...) работает во вложенных функциях, и как это не работает - PullRequest
0 голосов
/ 21 ноября 2018

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

Но я только что провел эксперимент, чтобы подтвердить это, и теперь мне кажется, что это неправильно.Таким образом:

> f02 <- function(...){
+   vv <- list(...)
+   print(vv)
+ }
> f01 <- function(...){
+   f02(b = 2)
+ }
> f01(a=1)
$`b`
[1] 2

Здесь внутренний эллипс, по-видимому, не унаследовал аргумент a=1 от внешнего эллипса.

Итак, моя текущая теория заключается в том, что когда вы выполняете действие, которое запрашиваетдля содержимого , такого как list(…), match.call(expand.dots=TRUE) или as.list(substitute(list(...)))[-1], вы получаете только первый экземпляр , который встречается, на основе пути поиска при нормальных правилах области видимости.Но я должен сказать, что это кажется мне маловероятным.Если бы это было так, то, например, графические параметры, переданные в функцию построения нескольких вызовов вниз, страдали бы загадочными сбоями, если бы одна из промежуточных функций имела аргумент .

Поэтому мне интересно, есть ли какие-тоспециальные правила для определения параметров аргументов, которые ищутся в точечных точках, такие как поиск улучшенного экземпляра, если локальный пустой, или если вы ищете в конкретный именованный аргумент, скажем list(...)$my_parameter, и не находитеэто там .Ни одно из этих решений не кажется мне очень правдоподобным, но, в общем-то, ни одно из предложенных мною решений не подходит.

Предыдущие вопросы по этой теме, похоже, были сосредоточены главным образом на различных крайних случаях.Я ищу больше для понимания правил прохождения в обычном случае (но, возможно, с несколькими уровнями вызовов).

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Я надеюсь, что форум позволит мне опубликовать ответ и по-прежнему принимать ответ йода.Это мое намерение.

Похоже, что мое первоначальное убеждение - что точки накапливают все аргументы, предоставленные им в стеке вызовов, - верно, при условии, что многоточие (...) включено в оба определения функций и вызовы функций для всех вызовов, дополнительных к первым.Смотрите код ниже.Для меня это говорит о том, что аргумент ... должен обычно добавляться к вызовам функций, встроенным в другие функции, если есть какая-либо вероятность того, что вспомогательным функциям где-то в цепочке может понадобиться аргумент, предоставленный на верхнем уровне, который нельзя идентифицировать и передатьявно, когда функция написана.Если у кого-то, читающего это, есть веские основания полагать, что это плохая идея, я хотел бы услышать об этом.

Обратите внимание, что хотя многоточие требуется в вызовах функций 2 и 3 для передачи ихаргументы внутрь, это запрещено на верхнем уровне, что приводит к ошибке '...' used in an incorrect context.Я нахожу это загадочным.Я ожидал бы ошибку '...' not found, учитывая, что точки разрешены во вспомогательных вызовах.

Кроме того, я не понимаю, почему имя третьего аргумента сообщается как `c`.Это не потому, что c является именем функции;то же самое происходит с c1.

> f03 <- function(...){
+   vv <- list(...)
+   print(vv)
+ }
> f02 <- function(...){
+   f03(c = 3, ...)
+ }
> f01 <- function(...){
+   f02(b = 2, ...)
+ }
> f01(a = 1)
$`c`
[1] 3

$b
[1] 2

$a
[1] 1
0 голосов
/ 21 ноября 2018

Многоточие должно быть явно предоставлено для передачи во вложенную функцию, поэтому, например, в вашем f02 вызов list получает то, что было передано в f02 в качестве своих собственных аргументов.Напротив, в f01 аргументы просто игнорируются.Вы можете передать аргументы в f02 внутри f01 следующим образом:

  f01 <- function(...){
  f02(b = 2,...)
}

Результат:

f01(a=1)
$b
[1] 2

$a
[1] 1

Это работает независимо от количества аргументов в многоточии:

f01(a=1,c=3)
$b
[1] 2

$a
[1] 1

$c
[1] 3
...