To ciekawa dyskusja. Myślę, że przykład @ flodel jest doskonały. Myślę jednak, że to ilustruje mój punkt (i @koshke wspomina o tym w komentarzu), który returnma sens, gdy używasz trybu rozkazującego zamiast funkcjonalnego stylu kodowania .
Nie chcę się nad tym zastanawiać, ale napisałbym footak:
foo = function() ifelse(a,a,b)
Funkcjonalny styl pozwala uniknąć zmian stanu, takich jak przechowywanie wartości output. W tym stylu returnjest nie na miejscu; foowygląda bardziej jak funkcja matematyczna.
Zgadzam się z @flodel: użycie skomplikowanego systemu zmiennych boolowskich w barbyłoby mniej jasne i bezcelowe, jeśli masz return. To, co czyni bartak podatnymi na returnoświadczenia, polega na tym, że jest napisane w trybie rozkazującym. Rzeczywiście, zmienne logiczne reprezentują zmiany „stanu”, których uniknięto w stylu funkcjonalnym.
Naprawdę trudno jest przepisać barw funkcjonalnym stylu, ponieważ jest to tylko pseudokod, ale pomysł jest mniej więcej taki:
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.
}
whilePętla byłaby najtrudniejsza przepisać, ponieważ jest kontrolowane przez państwo do zmian a.
Utrata prędkości spowodowana wywołaniem returnjest znikoma, ale wydajność uzyskana dzięki unikaniu returni przepisywaniu w funkcjonalnym stylu jest często ogromna. Powiedzenie nowym użytkownikom, aby przestali używać, returnprawdopodobnie nie pomoże, ale wprowadzenie ich do funkcjonalnego stylu przyniesie korzyści.
@Paul returnjest konieczny w trybie rozkazującym, ponieważ często chcesz wyjść z funkcji w różnych punktach pętli. Funkcjonalny styl nie używa pętli, a zatem nie potrzebuje return. W czysto funkcjonalnym stylu ostateczne wywołanie jest prawie zawsze pożądaną wartością zwrotną.
W Pythonie funkcje wymagają returninstrukcji. Jeśli jednak zaprogramowałeś swoją funkcję w stylu funkcjonalnym, prawdopodobnie będziesz mieć tylko jedną returninstrukcję: na końcu swojej funkcji.
Korzystając z przykładu z innego postu StackOverflow, powiedzmy, że potrzebujemy funkcji, która zwróci, TRUEjeśli wszystkie wartości w danym odcinku będą xnieparzyste. Możemy użyć dwóch stylów:
# 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)
W stylu funkcjonalnym zwracana wartość naturalnie spada na końcu funkcji. Ponownie wygląda bardziej jak funkcja matematyczna.
@GSee Przedstawione ostrzeżenia ?ifelsesą zdecydowanie interesujące, ale nie sądzę, aby próbowały zniechęcić do korzystania z tej funkcji. W rzeczywistości ifelsema tę zaletę, że automatycznie wektoryzuje funkcje. Na przykład rozważ nieco zmodyfikowaną wersję foo:
foo = function(a) { # Note that it now has an argument
if(a) {
return(a)
} else {
return(b)
}
}
Ta funkcja działa dobrze, gdy length(a)jest 1, ale jeśli przepisałeś ponownie fooza pomocąifelse
foo = function (a) ifelse(a,a,b)
Teraz foodziała na dowolnej długości a. W rzeczywistości zadziałałoby nawet, gdy ajest matrycą. Zwracanie wartości tego samego kształtu co testfunkcja ułatwiająca wektoryzację, a nie problem.
returnjest niepotrzebny nawet w ostatnim przykładzie. Usunięciereturnmoże trochę przyspieszyć, ale moim zdaniem dzieje się tak, ponieważ mówi się, że R jest funkcjonalnym językiem programowania.