Чтобы проверить, проблема в том, что substitute
является вложенным.
Когда R смотрит на foobar(a)
, он запускает test(foo)
в foobar
функция, и поэтому переменная, на которую смотрит функция test
, называется foo
.
Я начну с игрушечного примера, чтобы упростить объяснение.Функция library
, как и ваша test
функция, интерпретирует свой аргумент через имя переменной.то есть library(MASS)
загружает библиотеку 'MASS', а не строку, которая содержится внутри переменной 'MASS'.
Теперь я создам функцию f
, которая просто вызывает library
- это отражает вашеfoobar
функция:
f <- function(x) {
library(x)
}
Теперь давайте попробуем:
> f(MASS)
Error in library(x) : there is no package called ‘x’
О нет!Это не сработало!Как так?Поскольку помните, в коде library
, он подставляет переданную переменную. То есть library <- function(lib,...) substitute(lib)
.
Так что f(MASS)
переходит к function(x) library(x)
,и, следовательно, я набрал library(x)
прямо в командной строке - library
только пытается загрузить x
, а не * x 1040 * значение , MASS
.
OKмы можем это исправить: нам просто нужно изменить library(x)
на library(substitute(x))
, так как substitute(x)
равно MASS
, и мы тогда получим library(MASS)
, верно?
f <- function(x) {
library(substitute(x))
}
Давайте попробуем:
> f(MASS)
Error in library(substitute(x)) : 'package' must be of length 1
Ух, что случилось?В пределах f
, substitute(x)
- это , который не оценивается , потому что library
целенаправленно не оценивает выражение, которое он получает, потому что затем набирает library(MASS)
в командестрока не будет работать.
Поэтому мы действительно хотим сохранить substitute(x)
в качестве переменной и затем выполнить library
для этой переменной.
Единственная проблема в том, что даже если мы делаем y <- substitute(x); library(y)
в f
, мы всегда сталкиваемся с этой проблемой, что аргумент, введенный в library
, никогда не оценивается .Выполнение этого приведет к тому же, что и первая ошибка: «нет пакета с именем y
».
Как мы можем это исправить?Нам нужно как-то косвенно вызвать library
с substitute(x)
в качестве аргумента, где substitute(x)
равно оценивается .
Ага!Мы можем использовать do.call
!(примечание: я не придумал это самостоятельно, я руководствовался этим сообщением в списке рассылки R по вложенным заменителям :
f <- function(x) {
do.call(library,list(substitute(x)))
}
Это ровно то, что мы хотим - он вызывает library
, но передает substitute(x)
в качестве библиотеки. Сначала оценивает substitute(x)
, поскольку мы прямо не написали library(substitute(x))
.
> f(MASS) # no error!
# see if MASS is loaded - check if function 'lda' is there:
> exists('lda',mode='function')
[1] TRUE # huzzah!
Решение для вашего дела
Итак, применяя этот урок к вашему вопросу, попробуйте:
foobar <- function(foo)
{
if ( do.call(test,list(substitute(foo))) ) # see the do.call & substitute?
cat ("Yes, I have foo! \n")
else
cat("Sorry, not a valid foo")
}
Давайте посмотрим:
> ls()
[1] "foobar" "test"
> test(a)
[1] FALSE
> a <- 'foobar'
> test(a)
[1] FALSE
> a <- 1
> test(a)
[1] TRUE
> foobar(a)
Yes, I have foo!
Huzzah! (Кстати: спасибо, что задали этот вопрос, потому что ответ - это то, что я всегда хотел знать).