Как программно создать функцию R?

Недавно Хэдли Уикхэм задал интересный вопрос о списке рассылки r-devel и не смог найти существующий вопрос по теме в StackOverflow, я подумал, что это может быть полезно и для него.

Перефразируем:

Функция R состоит из трех элементов: списка аргументов, тела и среды. Можем ли мы построить функцию программно из этих трех элементов?

(Достаточно исчерпывающий ответ достигается в конце streamа в ссылке r-devel выше. Я оставлю это открытым для других, чтобы воссоздать бенчмаркинг различных решений и предоставить его в качестве ответа, но не забудьте привести Хэдли если вы это сделаете. Если никто не встанет через несколько часов, я сделаю это сам.)

Это расширение на обсуждение здесь .

Наши три части должны быть списком аргументов, телом и средой.

Для среды мы просто используем env = parent.frame() по умолчанию.

Нам не нужен обычный старый список аргументов, поэтому вместо этого мы используем alist который имеет другое поведение:

«… значения не оцениваются, а помеченные аргументы без значения допускаются»

 args <- alist(a = 1, b = 2) 

Для тела мы приводим наше выражение, чтобы call :

 body <- quote(a + b) 

Один из вариантов - преобразовать args в список пар, а затем просто вызвать функцию function используя eval :

 make_function1 <- function(args, body, env = parent.frame()) { args <- as.pairlist(args) eval(call("function", args, body), env) } 

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

 make_function2 <- function(args, body, env = parent.frame()) { f <- function() {} formals(f) <- args body(f) <- body environment(f) <- env f } 

Третий вариант - просто использовать as.function :

 make_function3 <- function(args, body, env = parent.frame()) { as.function(c(args, body), env) } 

И, наконец, это кажется очень похожим на первый метод для меня, за исключением того, что мы используем несколько другую идиому для создания вызова функции, используя substitute а не call :

 make_function4 <- function(args, body, env = parent.frame()) { subs <- list(args = as.pairlist(args), body = body) eval(substitute(`function`(args, body), subs), env) } library(microbenchmark) microbenchmark( make_function1(args, body), make_function2(args, body), make_function3(args, body), make_function4(args, body), function(a = 1, b = 2) a + b ) Unit: nanoseconds expr min lq median uq max 1 function(a = 1, b = 2) a + b 187 273.5 309.0 363.0 673 2 make_function1(args, body) 4123 4729.5 5236.0 5864.0 13449 3 make_function2(args, body) 50695 52296.0 53423.0 54782.5 147062 4 make_function3(args, body) 8427 8992.0 9618.5 9957.0 14857 5 make_function4(args, body) 5339 6089.5 6867.5 7301.5 55137 

Существует также проблема создания alist объектов программно, поскольку это может быть полезно для создания функций, когда число аргументов является переменным.

alist – просто именованный список пустых символов. Эти пустые символы могут быть созданы с помощью substitute() . Так:

 make_alist <- function(args) { res <- replicate(length(args), substitute()) names(res) <- args res } identical(make_alist(letters[1:2]), alist(a=, b=)) ## [1] TRUE 
  • Встроенная функция связи
  • Вычисление средней функции массива Swift
  • Почему std :: function не равнозначно сопоставимо?
  • Как ключевые слова IMMUTABLE, STABLE и VOLATILE влияют на поведение функции?
  • Последняя непустая ячейка в столбце
  • Разрешение перегрузки C ++
  • Вывод сигнатуры вызова lambda или произвольного вызываемого для «make_function»
  • Как объяснить обратные вызовы на простом английском языке? Как они отличаются от вызова одной функции от другой функции?
  • В MATLAB, могу ли я иметь скрипт и определение функции в том же файле?
  • Как строки передаются в .NET?
  • Функция триггера jquery, когда элемент находится в viewport
  • Давайте будем гением компьютера.