Konspekt
Transkrypt
Konspekt
Konspekt • Teoria • Matematyczny przykład rekurencji • Notacja typów i zazwyczaj stosowane typy w przetwarzaniu rekurencyjnym • Przykład 1: maximum • Przykład 2: replicate • Przykład 3: reverse • Przykład 4: quicksort • Podsumowanie 1 Rekurencja Teoria Rekurencja to w logice, programowaniu i w matematyce odwoływanie się na przykład funkcji lub definicji do samej siebie. • Haskell jest językiem czysto funkcyjnym. Konsekwencją tego jest brak pętli znanych z imperatywnych języków programowania. • Z pomocą języków funkcyjnych definiujemy algorytmy poprzez zdefiniowanie tego co a nie jak ma być wykonane. Matematyczny przykład rekurencji fib (0) = 0 fib (1) = 1 fib (n) = fib(n-1) + fib(n-2) dla n >= 2 Przy projektowaniu funkcji rekurencyjnych należy zwrócić uwagę na: • Strukturę danych, która ma być przekazana funkcji (Najczęściej są to listy lub krotki) • Strukturę danych, która ma być zwracana przez funkcję • Warunek zakończenia 2 Notacja typów i zazwyczaj stosowane typy w przetwarzaniu rekurencyjnym Dwie najważniejsze struktury danych używane przy rekurencji • Krotka (Tuple) Krotka może przechowywać elementy różnych typów • Lista (List) Wszystkie elementy listy muszą być tego samego typu Notacja funkcji zip zip :: [a] -> [b] -> [(a,b)] > zip [1,2,3] [2,3] [(1,2), (2,3)] Przykład struktury przedstawiającej punkty w przestrzeni dwuwymiarowej [(3,3), (3,0), (0,0), (0,3)] 3 Przykład 1: maximum Przykład użycia > maximum’ [2,5,1] 5 Typ maximum’ :: (Ord a) => [a] -> a 4 Implementacja maximum’ :: (Ord a) => [a] -> a maximum’ [] = error "maximum of empty list" maximum’ [x] = x maximum’ (x:xs) | x > maxTail = x | otherwise = maxTail where maxTail = maximum ’xs Wyjaśnienie > maximum’ [2,5,1] --> 2 [5,1] -> 5 [1] > 1 --> 2 [5,1] -> 5 [1] > 1 (if 2 > 5) (if 5 > 1) (warunek końcowy) 5 Przykład 2: replicate Przykład użycia > replicate 3 5 [5,5,5] Typ replicate’ :: (Num i, Ord i) => i -> a -> [a] 6 Implementacja replicate’ replicate’ | n <= replicate’ :: (Num i, Ord i) => i -> a -> [a] n _ 0 = [] n v = v : replicate’ (n-1) v replicate’ :: (Num i, Ord i) => i -> a -> [a] replicate’ n x | n <= 0 = [] | otherwise = x:replicate’ (n-1) x 7 Przykład 3: reverse Przykład użycia > reverse [1..3] [3,2,1] Typ reverse’ :: [a] -> [a] 8 Implementacja reverse’ :: [a] -> [a] reverse’ [] = [] reverse’ (x:xs) = reverse’ xs ++ [x] 9 Przykład 4: quicksort Przykład użycia > quicksort [10,2,5,3,1,6,7,4,2,3,4,8,9] > [1,2,2,3,3,4,4,5,6,7,8,9,10] Typ quicksort :: (Ord a) => [a] -> [a] 10 Implementacja quicksort :: (Ord a) => [a] -> [a] quicksort [] = [] quicksort (x:xs) = let smallerSorted = quicksort [a | a <- xs, a <= x] biggerSorted = quicksort [a | a <- xs, a > x] in smallerSorted ++ [x] ++ biggerSorted Wyjaśnienie quicksort [5,1,9,4,6,7,3] ----> ---> --> -> [5,1,9,4,6,7,3] [1,4,3] ++ [5] ++ [9,6,7] [] ++ [1] ++ [4,3] [6,7] ++ [9] ++ [] [3] ++ [4] ++ [] [] ++ [6] ++ [7] 11 Przykład 5: repeat Przykład użycia > take 3 (repeat 5) [3,3,3] Typ repeat’ :: a -> [a] Implementacja repeat’ x = x:repeat’ x 12 Podsumowanie Proces tworzenia funkcji rekurencyjnych wpasowuje się w pewien schemat. Zazwyczaj, najpierw definiowane są warunku końcowe, a następnie należy stworzyć funkcję, która wykonuje operację pomiędzy danym elementem (zazwyczaj głowa listy) i resztą listy. Przydatne przy projektowaniu funkcji w Haskellu może okazać się wartościowanie leniwe, gdzie funkcja rekurencyjna nie ma warunku końcowego. 13