Questa è una discussione interessante Penso che l'esempio di @ flodel sia eccellente. Tuttavia, penso che illustri il mio punto (e @koshke lo menziona in un commento) che returnha senso quando si utilizza uno stile di codifica imperativo anziché funzionale .
Per non ribadire il punto, ma avrei riscritto in fooquesto modo:
foo = function() ifelse(a,a,b)
Uno stile funzionale evita i cambiamenti di stato, come la memorizzazione del valore di output. In questo stile, returnè fuori posto; foosembra più una funzione matematica.
Sono d'accordo con @flodel: l'uso di un intricato sistema di variabili booleane barsarebbe meno chiaro e inutile quando lo hai fatto return. Ciò che rende barcosì suscettibile alle returndichiarazioni è che è scritto in uno stile imperativo. In effetti, le variabili booleane rappresentano i cambiamenti di "stato" evitati in uno stile funzionale.
È davvero difficile riscrivere barin stile funzionale, perché è solo uno pseudocodice, ma l'idea è qualcosa del genere:
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.
}
Il whileciclo sarebbe il più difficile da riscrivere, perché è controllato dalle modifiche di stato a a.
La perdita di velocità causata da una chiamata returnè trascurabile, ma l'efficienza ottenuta evitando returne riscrivendo in uno stile funzionale è spesso enorme. Dire ai nuovi utenti di smettere di usare returnprobabilmente non sarà d'aiuto, ma guidarli verso uno stile funzionale ne trarrà vantaggio.
@Paul returnè necessario in stile imperativo perché spesso vuoi uscire dalla funzione in diversi punti in un ciclo. Uno stile funzionale non utilizza i loop e quindi non è necessario return. In uno stile puramente funzionale, la chiamata finale è quasi sempre il valore di ritorno desiderato.
In Python, le funzioni richiedono a return un'istruzione. Tuttavia, se hai programmato la tua funzione in uno stile funzionale, probabilmente ne avrai solo unareturn frase: alla fine della tua funzione.
Usando un esempio da un altro post StackOverflow, supponiamo di volere una funzione che restituisca TRUEse tutti i valori in un datox avessero una lunghezza dispari. Potremmo usare due stili:
# 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 uno stile funzionale, il valore da restituire cade naturalmente alle estremità della funzione. Ancora una volta, sembra più una funzione matematica.
@Vedi Gli avvertimenti delineati ?ifelsesono decisamente interessanti, ma non credo che stiano cercando di dissuadere l'uso della funzione. In effetti, ifelseha il vantaggio di vettorializzare automaticamente le funzioni. Ad esempio, considera una versione leggermente modificata di foo:
foo = function(a) { # Note that it now has an argument
if(a) {
return(a)
} else {
return(b)
}
}
Questa funzione è valida quando length(a)è 1. Ma se si riscrive foocon unifelse
foo = function (a) ifelse(a,a,b)
Ora foofunziona su qualsiasi lunghezza di a. In effetti, funzionerebbe anche quando aè una matrice. Restituire un valore della stessa forma di testuna funzione che aiuta con la vettorializzazione, non è un problema.
returnnon è necessario nemmeno nell'ultimo esempio. La rimozionereturnpuò rendere un po 'più veloce, ma a mio avviso ciò è dovuto al fatto che R è un linguaggio di programmazione funzionale.