2017-02-05 17 views
3

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().

Есть ли причина, по которой я должен считать мой подход более низким? Я стараюсь избегать ненужного гнездования.

+1

Подход Eval не позволяет прекомпиляцию. Возможно, это также можно использовать в сценарии инъекции кода. Но это незначительные проблемы для непродуктивного кода. –

+0

Что касается вопросов безопасности - правильно ли я говорю, что нет никакой пользы от 'eval()', если оператор функции не выполняет проверку, если поставляемая функция имеет белый список? – mjktfw

+0

На самом деле, если вы используете 'eval (,,)', а не 'eval (parse (..))', возможно, мои возражения не выполняются. –

ответ

3
  • Одним из важных аспектов программной инженерии является то, что функции легко для тестирования и упаковки, выражения не так много. Поэтому, если вы используете функциональный подход , вы можете написать модульные тесты и поместить их в пакет. С помощью подхода eval вы ограничены собственным тестированием REPL. Очевидно, что мы все должны делать «Test Driven Development», по крайней мере, на нашем производственном коде, и ничто не должно выходить за дверь без набора модульных тестов, которые бы максимально экономически оправдывали код . Это облегчает жизнь людям (включая вас), которым, возможно, когда-нибудь понадобится внести изменения.

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

  • Еще один момент, который возникает для меня, заключается в том, что маршрут eval не является масштабируемым, то есть практическим только для выражений до определенной сложности. Использование функций, с другой стороны, позволяет вашей логике расти до любого практического размера.

  • И, наконец, eval как конструкция очень мощная, но одна из которых может вызвать у вас неприятности, вроде как использование мощного лазера до разрезанной бумаги. Так как его часто легко реализовать, он существует на многих языках , и в сети много статей о том, почему это опасно - вы должны смотреть на них. Так как этот мощный лазер, вы не должны действительно получать в привычке использовать его, кроме случаев, когда это необходимо.

 Смежные вопросы

  • Нет связанных вопросов^_^