Это интересная дискуссия. Я думаю, что пример @ 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 называется функциональным языком программирования.