Hadley's «Advanced R» дает нам краткое представление о функциональном программировании и возможных применениях «функциональных операторов». Однако я обеспокоен тем, что я либо не совсем понимаю, как это упрощает код, либо неохотно следует за некоторыми плохими методами, используя другие решения.Операторы функций и функции в R
Вместо создания операторов, ожидающих ввода функции, я создаю оболочку, которая принимает выражение в качестве своего аргумента и возвращает полный вывод (вместо функции, которую еще нужно вызвать). См. Пример:
# function operator
delay_by <- function(delay, f) {
function(...) {
Sys.sleep(delay)
f(...)
}
}
# simple wrapper
delay_by2 <- function(expr, delay) {
Sys.sleep(delay)
eval(expr)
}
delay_by(1, sqrt)(2)
delay_by2(sqrt(2), 1)
operator <- delay_by(1, sqrt)
wrapper <- function(x) delay_by2(sqrt(x), 1)
operator(2)
wrapper(2)
Этот подход все еще позволяет загружать функционалы (sapply и т. Д.) И применять memoisation. Кроме того, это поддерживает трубопроводы с %>%
.
lapply(1:10, function(x) sqrt(x) %>% delay_by2(1))
Возможный недостаток этого решения заключается в том, что он не создает постоянные среды выполнения для хранения переменных, сохранив функцию состояния, но они могут быть созданы явно с <<- new.env()
.
Есть ли причина, по которой я должен считать мой подход более низким? Я стараюсь избегать ненужного гнездования.
Подход Eval не позволяет прекомпиляцию. Возможно, это также можно использовать в сценарии инъекции кода. Но это незначительные проблемы для непродуктивного кода. –
Что касается вопросов безопасности - правильно ли я говорю, что нет никакой пользы от 'eval()', если оператор функции не выполняет проверку, если поставляемая функция имеет белый список? – mjktfw
На самом деле, если вы используете 'eval (,,)', а не 'eval (parse (..))', возможно, мои возражения не выполняются. –