Il s'agit d'une discussion intéressante. Je pense que l'exemple de @flodel est excellent. Cependant, je pense qu'il illustre mon point de vue (et @koshke le mentionne dans un commentaire) selon lequel return
a un sens lorsque vous utilisez un impératif au lieu d'un fonctionnel style de codage .
Je ne veux pas insister sur le point, mais j'aurais réécrit foo
comme ça :
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, return
n'est pas à sa place ; foo
ressemble plus à une fonction mathématique.
Je suis d'accord avec @flodel : l'utilisation d'un système complexe de variables booléennes en bar
serait moins claire, et inutile lorsque vous avez return
. Ce qui fait bar
si favorable à return
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 bar
en style fonctionnel, parce que c'est juste du pseudocode, mais l'idée est quelque chose comme ça :
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 while
serait la plus difficile à réécrire, parce qu'elle est contrôlée par les changements d'état de la boucle a
.
La perte de vitesse causée par un appel à return
est négligeable, mais l'efficacité gagnée en évitant return
et la réécriture dans un style fonctionnel est souvent énorme. Dire aux nouveaux utilisateurs d'arrêter d'utiliser return
ne sera probablement pas utile, mais les guider vers un style fonctionnel sera payant.
@Paul return
est nécessaire dans le style impératif parce que 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 de return
. Dans un style purement fonctionnel, l'appel final est presque toujours la valeur de retour souhaitée.
En Python, les fonctions nécessitent un return
déclaration. Toutefois, si vous avez programmé votre fonction dans un style fonctionnel, vous n'aurez probablement qu'une seule instruction return
déclaration : à la fin de votre fonction.
En utilisant un exemple tiré d'un autre billet de StackOverflow, disons que nous voulons une fonction qui renvoie TRUE
si toutes les valeurs d'un x
avait une longueur étrange. On pourrait 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 à retourner tombe naturellement aux extrémités de la fonction. Là encore, cela ressemble davantage à une fonction mathématique.
@GSee Les avertissements soulignés dans ?ifelse
sont certainement intéressants, mais je ne pense pas qu'ils essaient de dissuader l'utilisation de la fonction. En fait, ifelse
a 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 lorsque length(a)
est 1. Mais si vous réécrivez foo
avec un ifelse
foo = function (a) ifelse(a,a,b)
Maintenant foo
fonctionne sur toute longueur de a
. En fait, ça marcherait même quand a
est une matrice. En retournant une valeur de la même forme que test
est une fonctionnalité qui aide à la vectorisation, pas un problème.
13 votes
return
est inutile, même dans le dernier exemple. Suppression dereturn
peut le rendre un peu plus rapide, mais à mon avis, c'est parce que R est dit être un langage de programmation fonctionnel.5 votes
@kohske Pourriez-vous développer votre commentaire dans une réponse, en incluant plus de détails sur la raison pour laquelle c'est plus rapide, et comment cela est lié au fait que R est un langage de programmation fonctionnel ?
2 votes
return
induit un saut non-local, et le saut non-local explicite est inhabituel pour FP. En fait, par exemple, le schéma n'a pasreturn
. Je pense que mes commentaires sont trop courts (et peut-être incorrects) comme réponse.2 votes
F# n'a pas
return
,break
,continue
non plus, ce qui est parfois fastidieux.