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