TL; DR: Czy języki funkcjonalne lepiej radzą sobie z rekurencją niż języki niefunkcjonalne?
Obecnie czytam Code Complete 2. W pewnym momencie książki autor ostrzega nas przed rekurencją. Mówi, że należy tego unikać, gdy jest to możliwe, a funkcje wykorzystujące rekurencję są na ogół mniej skuteczne niż rozwiązanie wykorzystujące pętle. Na przykład autor napisał funkcję Java, używając rekurencji do obliczenia silni liczby w ten sposób (może nie być dokładnie taka sama, ponieważ w tej chwili nie mam ze sobą książki):
public int factorial(int x) {
if (x <= 0)
return 1;
else
return x * factorial(x - 1);
}
Jest to przedstawiane jako złe rozwiązanie. Jednak w językach funkcjonalnych używanie rekurencji jest często preferowanym sposobem działania. Na przykład tutaj jest funkcja silni w Haskell przy użyciu rekurencji:
factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n * factorial (n - 1)
I jest powszechnie akceptowane jako dobre rozwiązanie. Jak widziałem, Haskell bardzo często korzysta z rekurencji i nigdzie nie widziałem, żeby się jej skrzywiła.
Więc moje pytanie w zasadzie brzmi:
- Czy języki funkcjonalne lepiej radzą sobie z rekurencją niż języki niefunkcjonalne?
EDYCJA: Mam świadomość, że przykłady, których użyłem, nie są najlepsze do zilustrowania mojego pytania. Chciałem tylko zauważyć, że Haskell (i ogólnie języki funkcjonalne) znacznie częściej korzysta z rekurencji niż języki niefunkcjonalne.
factorial n = product [1..n]
jest bardziej zwięzły, wydajniejszy i nie przepełnia stosu dla dużych n
(a jeśli potrzebujesz zapamiętywania, wymagane są zupełnie inne opcje). product
jest zdefiniowany w kategoriach niektórych fold
, które są zdefiniowane rekurencyjnie, ale z najwyższą ostrożnością. Rekurencja jest akceptowalnym rozwiązaniem przez większość czasu, ale nadal łatwo jest zrobić to źle / nieoptymalnie.