Esta é uma discussão interessante. Eu acho que o exemplo do @ flodel é excelente. No entanto, acho que ilustra meu argumento (e o @koshke menciona isso em um comentário) que returnfaz sentido quando você usa um imperativo em vez de um estilo de codificação funcional .
Não para enfatizar a questão, mas eu teria reescrito fooassim:
foo = function() ifelse(a,a,b)
Um estilo funcional evita alterações de estado, como armazenar o valor de output. Nesse estilo, returnestá fora de lugar; fooparece mais uma função matemática.
Concordo com o @flodel: usar um sistema complexo de variáveis booleanas barseria menos claro e inútil quando você tiver return. O que torna bartão acessível às returndeclarações é que elas são escritas em um estilo imperativo. De fato, as variáveis booleanas representam as alterações de "estado" evitadas em um estilo funcional.
É realmente difícil reescrever barno estilo funcional, porque é apenas pseudocódigo, mas a ideia é algo como isto:
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.
}
O whileloop seria o mais difícil de reescrever, porque é controlado por alterações de estado em a.
A perda de velocidade causada por uma chamada para returné insignificante, mas a eficiência obtida ao evitar returne reescrever em um estilo funcional é muitas vezes enorme. Dizer aos novos usuários que parem de usar returnprovavelmente não ajudará, mas guiá-los para um estilo funcional resultará em recompensa.
@Paul returné necessário em estilo imperativo, porque muitas vezes você deseja sair da função em diferentes pontos de um loop. Um estilo funcional não usa loops e, portanto, não precisa return. Em um estilo puramente funcional, a chamada final é quase sempre o valor de retorno desejado.
No Python, as funções requerem uma returndeclaração. No entanto, se você programou sua função em um estilo funcional, provavelmente terá apenas uma returninstrução: no final de sua função.
Usando um exemplo de outra postagem StackOverflow, digamos que queremos uma função que retorne TRUEse todos os valores em um determinado xtiverem um comprimento ímpar. Nós poderíamos usar dois estilos:
# 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)
Em um estilo funcional, o valor a ser retornado naturalmente cai no final da função. Mais uma vez, parece mais uma função matemática.
@ GSee Os avisos descritos ?ifelsesão definitivamente interessantes, mas não acho que eles estejam tentando dissuadir o uso da função. De fato, ifelsetem a vantagem de vetorizar funções automaticamente. Por exemplo, considere uma versão ligeiramente modificada de foo:
foo = function(a) { # Note that it now has an argument
if(a) {
return(a)
} else {
return(b)
}
}
Esta função funciona bem quando length(a)é 1. Mas se você reescrever foocom umifelse
foo = function (a) ifelse(a,a,b)
Agora foofunciona em qualquer comprimento de a. De fato, funcionaria mesmo quando aé uma matriz. Retornar um valor da mesma forma que testum recurso que ajuda na vetorização, não é um problema.
returné desnecessário mesmo no último exemplo. A remoçãoreturnpode torná-lo um pouco mais rápido, mas, na minha opinião, isso ocorre porque R é considerado uma linguagem de programação funcional.