Почему match.call полезен?

В теле некоторых R-функций, например lm, я вижу вызовы функции match.call. Как говорится на странице справки, при использовании внутри функции match.call возвращается вызов, в котором указаны имена аргументов; и это должно быть полезно для передачи большого количества аргументов другим функциям.

Например, в функции lm мы видим вызов функции model.frame

function (formula, data, subset, weights, na.action, method = "qr", 
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
contrasts = NULL, offset, ...) 
{
cl <- match.call()
mf <- match.call(expand.dots = FALSE)
m <- match(c("formula", "data", "subset", "weights", "na.action", 
    "offset"), names(mf), 0L)
mf <- mf[c(1L, m)]

mf$drop.unused.levels <- TRUE
mf[[1L]] <- quote(stats::model.frame)
mf <- eval(mf, parent.frame())

Почему это более полезно, чем прямое обращение к model.frame с указанием имен аргументов, как я делаю дальше?

function (formula, data, subset, weights, na.action, method = "qr", 
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
contrasts = NULL, offset, ...) 
{
mf <- model.frame(formula = formula, data = data,
                  subset = subset, weights = weights, subset = subset) 

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

Ответы

Ответ 1

Одна из причин, которая здесь имеет значение, заключается в том, что match.call захватывает язык вызова без его оценки, и в этом случае он позволяет lm обрабатывать некоторые "отсутствующие" переменные как "необязательные". Рассмотрим:

lm(x ~ y, data.frame(x=1:10, y=runif(10)))

Vs:

lm2 <- function (
  formula, data, subset, weights, na.action, method = "qr", 
  model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
  contrasts = NULL, offset, ...
) {
  mf <- model.frame(
    formula = formula, data = data, subset = subset, weights = weights
  ) 
}
lm2(x ~ y, data.frame(x=1:10, y=runif(10)))
## Error in model.frame.default(formula = formula, data = data, subset = subset,  :
##   invalid type (closure) for variable '(weights)'

В lm2, поскольку weights "отсутствует", но вы все еще используете его в weights=weights, R пытается использовать функцию stats::weights, которая явно не та, что была предназначена. Вы можете обойти это, проверив пропущенность, прежде чем называть model.frame, но в этот момент match.call начинает выглядеть довольно хорошо. Посмотрите, что произойдет, если мы debug вызываем:

debug(lm2)
lm2(x ~ y, data.frame(x=1:10, y=runif(10)))
## debugging in: lm2(x ~ y, data.frame(x = 1:10, y = runif(10)))
## debug at #5: {
##     mf <- model.frame(formula = formula, data = data, subset = subset,
##         weights = weights)
## }
Browse[2]> match.call()
## lm2(formula = x ~ y, data = data.frame(x = 1:10, y = runif(10)))

match.call не содержит отсутствующих аргументов.

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