Где обрабатываются отсутствующие точки (`...`)?

Если мы рассмотрим тело функции с точками ... в списке аргументов, мы обычно можем найти функцию, которая получает эти аргументы точек.

Например, мы можем видеть в теле sapply(), что аргументы точек передаются до lapply().

sapply
# function (X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE) 
# {
#     FUN <- match.fun(FUN)
#     answer <- lapply(X = X, FUN = FUN, ...)
#     ## rest of function body
# }
# <bytecode: 0x000000000e05f0b0>
# environment: namespace:base>

Однако в lapply() в списке аргументов есть точки ..., но не в теле функции.

lapply
# function (X, FUN, ...) 
# {
#     FUN <- match.fun(FUN)
#     if (!is.vector(X) || is.object(X)) 
#         X <- as.list(X)
#     .Internal(lapply(X, FUN))
# }
# <bytecode: 0x0000000009414f08>
# <environment: namespace:base>

Итак, где обрабатываются точки ... аргументов в lapply()? Что/куда они перешли? Мы не можем передать их на match.fun(). Я предполагаю, что они переданы в .Internal(), но я не вижу причин для этого работать, когда я не вижу, чтобы они передавались в любую функцию в теле функции.

Ответ 1

Они явно не передаются в .Internal, но я считаю, что они доступны для do_lapply (в src/main/apply.c) через динамическую область. Правила обзора могут несколько отличаться от обычных, поскольку .Internal является примитивной функцией.

Вы можете видеть, что ... (R_DotsSymbol) добавляется в вызов функции lapply создает, поэтому они доступны для вызова функции для каждого элемента списка. tmp примерно эквивалентен X[[i]], а R_fcall примерно эквивалентен FUN(X[[i]], ...).

SEXP tmp = PROTECT(LCONS(R_Bracket2Symbol,
        LCONS(X, LCONS(isym, R_NilValue))));
SEXP R_fcall = PROTECT(LCONS(FUN,
             LCONS(tmp, LCONS(R_DotsSymbol, R_NilValue))));