Це цікава дискусія. Я думаю, що приклад @ flodel є відмінним. Однак я думаю, що це ілюструє мою думку (а @koshke це згадує у коментарі), яка return
має сенс, коли ви використовуєте імператив замість функціонального стилю кодування .
Щоб не брати участь у цьому, я б переписав foo
так:
foo = function() ifelse(a,a,b)
Функціональний стиль дозволяє уникнути змін стану, як-от зберігання значення output
. У цьому стилі return
поза місцем;foo
більше нагадує математичну функцію.
Я згоден з @flodel: використання складної системи булевих змінних у bar
було б менш зрозумілим і безглуздим, коли у вас є return
. Що робить bar
так прихильнимreturn
тверджень, це те, що вони написані в обов'язковому стилі. Дійсно, булеві змінні являють собою "стан" змін, уникнених у функціональному стилі.
Переписати bar
у функціональному стилі дуже важко , тому що це просто псевдокод, але ідея приблизно така:
e_func <- function() do_stuff
d_func <- function() ifelse(any(sapply(seq(d),e_func)),2,3)
b_func <- function() {
do_stuff
ifelse(c,1,sapply(seq(b),d_func))
}
bar <- function () {
do_stuff
sapply(seq(a),b_func) # Not exactly correct, but illustrates the idea.
}
while
Цикл буде найбільш важко переписати, бо він знаходиться під контролем змін стану a
.
Втрати швидкості, викликані дзвінком return
, незначні, однак ефективність, досягнута уникненням return
та перезаписом у функціональному стилі, часто величезна. Скажіть новим користувачам припинити використання, return
ймовірно, не допоможе, але наведення їх на функціональний стиль принесе користь.
@Paul return
необхідний в імперативному стилі, тому що ви часто хочете вийти з функції в різних точках циклу. Функціональний стиль не використовує циклів, і тому не потребує return
. У чисто функціональному стилі, підсумковий виклик майже завжди є бажаним значенням повернення.
У Python функції вимагають return
оператора. Однак якщо ви запрограмували свою функцію у функціональному стилі, ви, швидше за все, матимете лише однуreturn
твердження: наприкінці своєї функції.
Використовуючи приклад з іншої публікації StackOverflow, скажімо, що ми хотіли, щоб функція поверталася, TRUE
якщо всі значення в заданій x
довжині мали непарну довжину. Ми можемо використовувати два стилі:
# Procedural / Imperative
allOdd = function(x) {
for (i in x) if (length(i) %% 2 == 0) return (FALSE)
return (TRUE)
}
# Functional
allOdd = function(x)
all(length(x) %% 2 == 1)
У функціональному стилі значення, яке повертається, природно падає на кінці функції. Знову ж таки, це більше схоже на математичну функцію.
@GSee Попередження, викладені в ?ifelse
, безумовно, цікаві, але я не думаю, що вони намагаються відмовити від використання функції. Фактично, ifelse
має перевагу автоматично векторизуючі функції. Наприклад, розгляньте трохи змінену версію foo
:
foo = function(a) { # Note that it now has an argument
if(a) {
return(a)
} else {
return(b)
}
}
Ця функція прекрасно працює, коли length(a)
дорівнює 1. Але якщо ви переписали foo
зifelse
foo = function (a) ifelse(a,a,b)
Зараз foo
працює на будь-якій довжині a
. Насправді це навіть спрацювало б, коли a
є матрицею. Повернення значення тієї самої форми, що test
і функція, яка допомагає векторизації, не є проблемою.
return
є непотрібним навіть в останньому прикладі. Видаленняreturn
може зробити його швидше трохи, але, на мій погляд, це тому, що R, як кажуть, є функціональною мовою програмування.