Esta es una discusión interesante. Creo que el ejemplo de @ flodel es excelente. Sin embargo, creo que ilustra mi punto (y @koshke lo menciona en un comentario) que returntiene sentido cuando se usa un estilo de codificación imperativo en lugar de uno funcional .
No para diferir el punto, pero habría reescrito fooasí:
foo = function() ifelse(a,a,b)
Un estilo funcional evita cambios de estado, como almacenar el valor de output. En este estilo, returnestá fuera de lugar; foose parece más a una función matemática.
Estoy de acuerdo con @flodel: usar un intrincado sistema de variables booleanas en barsería menos claro e inútil cuando lo tienes return. Lo que hace barque las returndeclaraciones sean tan favorables es que está escrito en un estilo imperativo. De hecho, las variables booleanas representan los cambios de "estado" evitados en un estilo funcional.
Es realmente difícil reescribir baren estilo funcional, porque es solo un pseudocódigo, pero la idea es algo como esto:
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.
}
El whilebucle sería el más difícil de reescribir, porque está controlado por cambios de estado a a.
La pérdida de velocidad causada por una llamada a returnes insignificante, pero la eficiencia obtenida al evitar returny reescribir en un estilo funcional a menudo es enorme. Decirles a los nuevos usuarios que dejen de usarlo returnprobablemente no ayudará, pero guiarlos hacia un estilo funcional dará resultado.
@Paul returnes necesario en un estilo imperativo porque a menudo desea salir de la función en diferentes puntos de un bucle. Un estilo funcional no usa bucles y, por lo tanto, no es necesario return. En un estilo puramente funcional, la llamada final es casi siempre el valor de retorno deseado.
En Python, las funciones requieren una returndeclaración. Sin embargo, si programó su función en un estilo funcional, es probable que solo tenga una returndeclaración: al final de su función.
Usando un ejemplo de otra publicación de StackOverflow, digamos que deseamos una función que devuelva TRUEsi todos los valores de un determinado xtienen una longitud impar. Podríamos usar dos 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)
En un estilo funcional, el valor que se devuelve cae naturalmente en los extremos de la función. De nuevo, se parece más a una función matemática.
@GSee Las advertencias descritas en ?ifelseson definitivamente interesantes, pero no creo que estén tratando de disuadir el uso de la función. De hecho, ifelsetiene la ventaja de vectorizar automáticamente las funciones. Por ejemplo, considere una versión ligeramente modificada de foo:
foo = function(a) { # Note that it now has an argument
if(a) {
return(a)
} else {
return(b)
}
}
Esta función funciona bien cuando length(a)es 1. Pero si reescribió foocon unifelse
foo = function (a) ifelse(a,a,b)
Ahora foofunciona en cualquier longitud de a. De hecho, incluso funcionaría cuando aes una matriz. Devolver un valor con la misma forma que testes una característica que ayuda con la vectorización, no es un problema.
returnes innecesario incluso en el último ejemplo. La eliminaciónreturnpuede hacer que sea un poco más rápido, pero en mi opinión esto se debe a que se dice que R es un lenguaje de programación funcional.