Implementacja rekurencji w języku Haskell Autorzy: Olaszewski Michał Witusiński Mateusz Piotrowski Radosław
Rekurencja Nazywana również rekursją, polega na wywołaniu przez funkcje samej siebie. Iteracja jest zastępowana przez algorytmy rekurencyjne. Zadania tak rozwiązywane sa wolniejsze od iteracyjnego odpowiednika, lecz rozwiązanie niektórych problemów jest wygodniejsze. Rekurencja jest często stosowana w matematyce. Implementacja powtarzających się czynności została rozwiązana przez rekurencję, ponieważ w języku Haskell nie istnieją takie instrukcje jak pętle, nie jest możliwa zmiana wartości zmiennej.
Przykład rekurencji – Ciąg Fibonacci’ego Jest to ciąg, gdzie każdy kolejny wyraz ciągu jest sumą dwóch poprzednich wyrazów. Dwa pierwsze elementy ciągu musimy wyznaczyć bez rekurencji. F0=0 F1=1 Fn=Fn-1+Fn-2, dla n≥2 Początkowe wartości to: 0,1,1,2,3,5,8,13,21,34…
Silnia Silnią liczby naturalnej n nazywamy iloczyn wszystkich dodatnich liczb naturalnych nie większych niż n. Oznaczamy za pomocą wykrzyknika (n!) i czytamy n silnia. Na przykład silnia z liczby 6 to 6 * 5 * 4 * 3 * 2 * 1 = 720. Składnia silni w Haskellu: silnia 0 = 1 silnia n = n * silnia (n-1)
W tym przypadku używamy Guards’a W tym przypadku używamy Guards’a. Zapobiega to wyjściu rekurencji dalej niż przewidujemy. Gdybyśmy nie użyli „otherwise=1” funkcja liczyłaby silnie również z liczb ujemnych dążących aż do minus nieskończoności.
Rekurencyjne mnożenie dwóch liczb Mnożenie można zapisać w sposób rekurencyjny Aby pomnożyć liczbę a razy liczbę b, bierzemy liczbę a i dodajemy do siebie b razy np. 2*5=2+2+2+2+2 Przypadkiem bazowym będzie mnożenie przez liczbę 0. Dowolna liczba pomnożona przez 0 daje 0. a * 0 = 0
Potęgowanie rekurencyjne Potęgę o wykładniku naturalnym definiujemy rekurencyjnie: a0 = 1 an = a * an−1 , dla n ≠ 0
Funkcja Maximum Funkcja maximum polega na zwracaniu największego elementu ze zbioru, dlatego musi być zabezpieczona ponieważ zbiór może być pusty, lub zawierać tylko jeden element.
Pierwszy warunek końcowy zwraca błąd jeśli nasza lista jest pusta Pierwszy warunek końcowy zwraca błąd jeśli nasza lista jest pusta. Max’ [] = error „Lista pusta” W wypadku jeśli jest to lista jednoelementowa - wynikiem będzie ten jeden element. Max’ [x] = x
W trzecim warunku końcowym rozłączamy naszą listę na głowę i ogon W trzecim warunku końcowym rozłączamy naszą listę na głowę i ogon. Używamy funkcji where w celu zdefiniowania funkcji maxTail, jako maximum reszty listy, a następnie sprawdzamy warunek (if) czy głowa jest większa od reszty listy. Jeśli tak- zwracamy głowę jako wynik. W innym wypadku zwracamy maximum reszty listy.
Weźmy tablicę liczb całkowitych [1,2,3] Weźmy tablicę liczb całkowitych [1,2,3]. Dzielimy tę tablicę na head(1) i tail(2,3) i wywołujemy funkcję maximum dla tail. Tail jest ponownie dzielony na head(2) i tail(3) w wyniku tego podziału mamy spełniony warunek końca rekurencji. Porównujemy 2 i 3, funkcja zwraca nam 3. Porównujemy wartość zwróconą w kroku 3 czyli 3 z head czyli 3. 3 jest większe od 1 zatem funkcja zwraca 3 jako największą wartość tablicy.
Funkcja duplicate Funkcja pobiera dwa argumenty z czego pierwszy to int, który odpowiada za ilość powtórzeń drugiego argumentu funkcji. Wynikiem działania tej funkcji jest lista powtarzających się elementów.
Przykładowe wywołanie funkcji: replicate 5 S zwraca nam listę [S,S,S,S,S]
Podsumowanie Każda definicja rekurencyjna potrzebuje przynajmniej jednego przypadku bazowego(nie rekurencyjnego). W przeciwnym wypadku nigdy się nie zakończy. W programowaniu rekurencja odgrywa bardzo ważną rolę.
DZIĘKUJEMY ZA UWAGĘ!