Пакет R: использование lapply для do.call списка внутренних функций - PullRequest
0 голосов
/ 08 мая 2018

Я разрабатываю пакет R, в котором у меня есть экспортированная функция, которая должна вызывать несколько неэкспортированных функций и сохранять результаты каждой из них в списке. То, какие функции вызываются, является переменным и зависит от ввода пользователя.

Мой подход к этому заключался в lapply (символьном) векторе имен функций с do.call, но, похоже, это делает неэкспортированные функции невидимыми для экспортируемой функции.

Рассмотрим следующий пример кода пакета:

tmp1 <- function(x) print(paste("Function 1 called with x =", x))
tmp2 <- function(x) print(paste("Function 2 called with x =", x))
tmp3 <- function(x) print(paste("Function 3 called with x =", x))

#' @export
test1 <- function() {
  tmp1("test")
  tmp2("test")
  tmp3("test")
}

#' @export
test2 <- function() {
  funs <- c("tmp1", "tmp2", "tmp3")
  for (fun in funs) do.call(fun, list(x = "test"))
}

#' @export
test3 <- function() {
  funs <- c("tmp1", "tmp2", "tmp3")
  lapply(funs, do.call, list(x = "test"))
}

После сборки и загрузки пакета запуск трех функций test дает следующий вывод:

test1()
#> [1] "Function 1 called with x = test"
#> [1] "Function 2 called with x = test"
#> [1] "Function 3 called with x = test"

test2()
#> [1] "Function 1 called with x = test"
#> [1] "Function 2 called with x = test"
#> [1] "Function 3 called with x = test"

test3()
#> Error in tmp1(x = "test"): could not find function "tmp1"

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

Итак, мой вопрос двоякий:

  1. Почему неэкспортированные функции невидимы для do.call при вызове внутри lapply?
  2. Можно ли заставить работать lapply(funs, do.call, list(...)) подход?

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

После комментариев к вопросу у меня есть (частичный) ответ:

  1. do.call по умолчанию оценивает символьные аргументы в parent.frame(), и при вызове внутри lapply это среда, отличная от той, в которой определены функции tmp (хотя я не уверен в специфике )
  2. Предоставление текущей среды для do.call делает подход lapply подходящим: lapply(funs, do.call, args = list(x = "test"), envir = environment())
0 голосов
/ 08 мая 2018

Это частично было рассмотрено в другом месте, я рекомендую вам прочитать эти два ( 1 , 2 ) здесь, в stackoverflow для глобальных переменных и назначения области видимости.

Чтобы решить вашу проблему, добавьте "<<-" при назначении ваших функций, т.е.

tmp1 <<- function(x) print(paste("Function 1 called with x =", x))
tmp2 <<- function(x) print(paste("Function 2 called with x =", x))
tmp3 <<- function(x) print(paste("Function 3 called with x =", x))

Выход:

> test1()
[1] "Function 1 called with x = test"
[1] "Function 2 called with x = test"
[1] "Function 3 called with x = test"
> 
> test2()
[1] "Function 1 called with x = test"
[1] "Function 2 called with x = test"
[1] "Function 3 called with x = test"
> test3()
[1] "Function 1 called with x = test"
[1] "Function 2 called with x = test"
[1] "Function 3 called with x = test"
[[1]]
[1] "Function 1 called with x = test"

[[2]]
[1] "Function 2 called with x = test"

[[3]]
[1] "Function 3 called with x = test"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...