Как я могу вызвать функцию пространства имен без оценки параметров, которые вы ей даете? - PullRequest
3 голосов
/ 01 декабря 2011

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

Call <- match.call(expand.dots = TRUE)
# Modify parameters here as needed and set unneeded ones to NULL.
Call[[1L]] <- as.name("name.of.function.to.be.called.here")
eval.parent(Call)

Однако, когда я помещаю имя в пространстве имен (например, utils::write.csv) в вызов as.name(), я получаю сообщение об ошибке:

"не удалось найти функцию" utils :: write.csv "

Как правильно использовать эту идиому для вызова функции пространства имен?

Ответы [ 2 ]

3 голосов
/ 01 декабря 2011

Вот решение, использующее do.call(), которое создает и оценивает вызов функции.

Как и подход, с которого вы начали, этот использует тот факт, что вызовы R являются списками, в которых: (а) первый элемент - это имя функции;и (b) все следующие элементы являются аргументами этой функции.

j <- function(x, file) {
    Call <- match.call(expand.dots = TRUE)
    arglist <- as.list(Call)[-1]
    do.call(utils::write.csv, arglist)
}

dat <- data.frame(x=1:10, y=rnorm(10))

j(dat, file="outfilename.csv")

EDIT: FWIW, вот пример из plot.formula в базе R, которыйиспользует конструкцию, аналогичную приведенной выше:

{
    m <- match.call(expand.dots = FALSE)
    eframe <- parent.frame()
    . . .
    . . . 
    m <- as.list(m)
    m[[1L]] <- stats::model.frame.default
    m <- as.call(c(m, list(na.action = NULL)))
    mf <- eval(m, eframe)
    . . .
    . . . 
}

Функция позже использует конструкцию do.call().Если немного углубиться в сорняки, то я прочел, что в показанном здесь фрагменте он использует несколько шагов, главным образом из-за необходимости добавить na.action=NULL в список аргументов.

В любом случае, этопохоже, что параметры do.call() настолько близки к каноническим, насколько это возможно.

1 голос
/ 01 декабря 2011

Как ответил @Josh O'Brien, do.call гораздо проще в использовании.

Первый аргумент do.call может быть либо именем функции, либо фактической функцией. Имя функции может NOT содержать квалификатор пространства имен. Часть :: на самом деле является функцией, которая берет имена с обеих сторон и находит соответствующую функцию, поэтому для работы она должна оцениваться отдельно.

Итак, с do.call вам нужно что-то вроде:

# ...Stuff from Josh's answer goes here
# And then:
do.call(utils::write.csv, arglist)

А с eval:

Call <- match.call(expand.dots = TRUE)
# Modify parameters here as needed and set unneeded ones to NULL.
Call[[1L]] <- utils::write.csv
eval.parent(Call)

Обратите внимание на отсутствие кавычек вокруг имени функции. Это приводит к закрытию функции.

Другой способ получить функцию от имени, указанного в пространстве имен:

eval(parse(text="utils::write.csv"))

Снова вызывается функция ::, которая корректно находит функцию.

Еще один ручной способ - извлечь имя пространства имен и имя функции, а затем выполнить поиск самостоятельно:

x <- strsplit("utils::write.csv", "::")[[1]]
get(x[2], asNamespace(x[1]))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...