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 return
ha senso quando si utilizza uno stile di codifica imperativo anziché funzionale .
Per non ribadire il punto, ma avrei riscritto in foo
questo 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; foo
sembra più una funzione matematica.
Sono d'accordo con @flodel: l'uso di un intricato sistema di variabili booleane bar
sarebbe meno chiaro e inutile quando lo hai fatto return
. Ciò che rende bar
così suscettibile alle return
dichiarazioni è che è scritto in uno stile imperativo. In effetti, le variabili booleane rappresentano i cambiamenti di "stato" evitati in uno stile funzionale.
È davvero difficile riscrivere bar
in 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 while
ciclo 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 return
e riscrivendo in uno stile funzionale è spesso enorme. Dire ai nuovi utenti di smettere di usare return
probabilmente 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 TRUE
se 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 ?ifelse
sono decisamente interessanti, ma non credo che stiano cercando di dissuadere l'uso della funzione. In effetti, ifelse
ha 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 foo
con unifelse
foo = function (a) ifelse(a,a,b)
Ora foo
funziona su qualsiasi lunghezza di a
. In effetti, funzionerebbe anche quando a
è una matrice. Restituire un valore della stessa forma di test
una funzione che aiuta con la vettorializzazione, non è un problema.
return
non è necessario nemmeno nell'ultimo esempio. La rimozionereturn
può rendere un po 'più veloce, ma a mio avviso ciò è dovuto al fatto che R è un linguaggio di programmazione funzionale.