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