Ceci est une discussion intéressante. Je pense que l'exemple de @ flodel est excellent. Cependant, je pense que cela illustre mon argument (et @koshke le mentionne dans un commentaire) qui a du returnsens lorsque vous utilisez un impératif au lieu d'un style de codage fonctionnel .
Sans trop insister, mais j'aurais réécrit foocomme ceci:
foo = function() ifelse(a,a,b)
Un style fonctionnel évite les changements d'état, comme le stockage de la valeur de output. Dans ce style, returnn'est pas à sa place; fooressemble plus à une fonction mathématique.
Je suis d'accord avec @flodel: utiliser un système complexe de variables booléennes dans barserait moins clair et inutile quand vous l'avez return. Ce qui rend barsi accessible aux returndéclarations, c'est qu'il est écrit dans un style impératif. En effet, les variables booléennes représentent les changements "d'état" évités dans un style fonctionnel.
Il est vraiment difficile de réécrire bardans un style fonctionnel, car il ne s'agit que de pseudocode, mais l'idée est quelque chose comme ceci:
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.
}
La whileboucle serait la plus difficile à réécrire, car elle est contrôlée par les changements d'état de a.
La perte de vitesse causée par un appel à returnest négligeable, mais l'efficacité obtenue en évitant returnet en réécrivant dans un style fonctionnel est souvent énorme. Dire aux nouveaux utilisateurs d'arrêter d'utiliser returnne sera probablement pas utile, mais les guider vers un style fonctionnel sera payant.
@Paul returnest nécessaire dans un style impératif car vous voulez souvent quitter la fonction à différents points d'une boucle. Un style fonctionnel n'utilise pas de boucles et n'a donc pas besoin return. Dans un style purement fonctionnel, l'appel final est presque toujours la valeur de retour souhaitée.
En Python, les fonctions nécessitent une returninstruction. Cependant, si vous avez programmé votre fonction dans un style fonctionnel, vous n'aurez probablement qu'une seule returninstruction: à la fin de votre fonction.
En utilisant un exemple d'un autre article StackOverflow, disons que nous voulions une fonction qui retournait TRUEsi toutes les valeurs d'une donnée xavaient une longueur impaire. Nous pourrions utiliser deux styles:
# 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)
Dans un style fonctionnel, la valeur à renvoyer tombe naturellement aux extrémités de la fonction. Encore une fois, cela ressemble plus à une fonction mathématique.
@GSee Les avertissements décrits dans ?ifelsesont certainement intéressants, mais je ne pense pas qu'ils essaient de dissuader l'utilisation de la fonction. En fait, ifelsea l'avantage de vectoriser automatiquement les fonctions. Par exemple, considérons une version légèrement modifiée de foo:
foo = function(a) { # Note that it now has an argument
if(a) {
return(a)
} else {
return(b)
}
}
Cette fonction fonctionne bien quand length(a)est 1. Mais si vous avez réécrit fooavec unifelse
foo = function (a) ifelse(a,a,b)
Fonctionne maintenant foosur n'importe quelle longueur de a. En fait, cela fonctionnerait même quand aest une matrice. Renvoyer une valeur de la même forme qu'une testfonctionnalité qui aide à la vectorisation, pas un problème.
returnest inutile même dans le dernier exemple. La suppressionreturnpeut accélérer un peu, mais à mon avis, c'est parce que R est dit être un langage de programmation fonctionnel.