Dies ist eine interessante Diskussion. Ich finde das Beispiel von @ flodel ausgezeichnet. Ich denke jedoch, dass dies meinen Punkt veranschaulicht (und @koshke erwähnt dies in einem Kommentar), returnder sinnvoll ist, wenn Sie einen Imperativ anstelle eines funktionalen Codierungsstils verwenden .
Nicht um den Punkt zu belabouren, aber ich hätte so umgeschrieben foo:
foo = function() ifelse(a,a,b)
Ein funktionaler Stil vermeidet Statusänderungen wie das Speichern des Werts von output. In diesem Stil returnist fehl am Platz; foosieht eher aus wie eine mathematische Funktion.
Ich stimme @flodel zu: Die Verwendung eines komplizierten Systems boolescher Variablen in barwäre weniger klar und sinnlos, wenn Sie dies getan haben return. Was Aussagen barso zugänglich macht , returnist, dass sie in einem imperativen Stil geschrieben sind. In der Tat stellen die booleschen Variablen die "Zustands" -Änderungen dar, die in einem funktionalen Stil vermieden werden.
Es ist wirklich schwierig, barim funktionalen Stil umzuschreiben , weil es nur ein Pseudocode ist, aber die Idee ist ungefähr so:
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.
}
Die whileSchleife wäre am schwierigsten umzuschreiben, da sie durch Zustandsänderungen an gesteuert wird a.
Der Geschwindigkeitsverlust, der durch einen Anruf bei verursacht wird, returnist vernachlässigbar, aber die Effizienz, die durch das Vermeiden returnund Umschreiben in einem funktionalen Stil erzielt wird, ist oft enorm. Es returnwird wahrscheinlich nicht helfen, neuen Benutzern zu sagen, dass sie die Verwendung einstellen sollen, aber es lohnt sich, sie zu einem funktionalen Stil zu führen.
@Paul returnist im imperativen Stil erforderlich, da Sie die Funktion häufig an verschiedenen Punkten in einer Schleife beenden möchten. Ein funktionaler Stil verwendet keine Schleifen und benötigt daher keine return. In einem rein funktionalen Stil ist der letzte Aufruf fast immer der gewünschte Rückgabewert.
In Python erfordern Funktionen eine returnAnweisung. Wenn Sie Ihre Funktion jedoch in einem funktionalen Stil programmiert haben, haben Sie wahrscheinlich nur eine returnAnweisung: am Ende Ihrer Funktion.
Nehmen wir an einem Beispiel aus einem anderen StackOverflow-Beitrag an, wir wollten eine Funktion, die zurückgegeben wird, TRUEwenn alle Werte in einem bestimmten Wert xeine ungerade Länge haben. Wir könnten zwei Stile verwenden:
# 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)
In einem funktionalen Stil fällt der zurückzugebende Wert natürlich an die Enden der Funktion. Wieder sieht es eher wie eine mathematische Funktion aus.
@GSee Die darin beschriebenen Warnungen ?ifelsesind definitiv interessant, aber ich glaube nicht, dass sie versuchen, die Verwendung der Funktion zu verhindern. In der Tat ifelsehat der Vorteil der automatischen Vektorisierung von Funktionen. Betrachten Sie beispielsweise eine leicht modifizierte Version von foo:
foo = function(a) { # Note that it now has an argument
if(a) {
return(a)
} else {
return(b)
}
}
Diese Funktion funktioniert gut, wenn 1 length(a)ist. Aber wenn Sie foomit einem neu geschrieben habenifelse
foo = function (a) ifelse(a,a,b)
Funktioniert jetzt fooauf jeder Länge von a. In der Tat würde es sogar funktionieren, wenn aes sich um eine Matrix handelt. Die Rückgabe eines Werts in der gleichen Form wie testein Feature, das bei der Vektorisierung hilft, ist kein Problem.
returnist auch im letzten Beispiel nicht notwendig. Das Entfernenreturnkann es etwas schneller machen, aber meiner Ansicht nach liegt dies daran, dass R eine funktionale Programmiersprache sein soll.