Table of Contents
#+title Ćwiczenia
1 Wymagania
Dla wszystkich funkcji należy jawnie podać typ. Powinien to być typ jak najogólniejszy.
2 Proste funkcje
2.1 Przykład: funkcja podzielnePrzez3
:
podzielnePrzez3 :: Integral a => a -> Bool podzielnePrzez3 n = n `mod` 3 == 0
2.2 Zadania
2.2.1 toSamo
Zdefiniować funkcję, która zwraca swój argument.
toSamo 3 |
⇒ 3 |
toSamo [1,2,3] |
⇒ [1,2,3] |
2.2.2 kwadrat
Zdefiniować funkcję, która zwraca kwadrat swojego argumentu.
kwadrat 3 |
⇒ 9 |
2.2.3 pusta
Zdefiniować funkcję, która sprawdza, czy lista jest pusta.
pusta [] |
⇒ True |
pusta [1,2,3] |
⇒ False |
3 Funkcje rekurencyjne
3.1 Zadania
3.1.1 silnia
3.1.2 fibonacci
3.1.3 ileRazyPrzez
Zdefiniować funkcję, która sprawdza, ile razy liczba jest podzielna bez reszty przez 3.
ileRazyPrzez 2 24 |
⇒ 3 |
ileRazyPrzez 7 9 |
⇒ 0 |
4 Obliczenia rekurencyjne na listach
4.1 Zadania
4.1.1 długość
Zdefiniować funkcję, która zwraca długość listy.
długość [] |
⇒ 0 |
długość [1,2,3] |
⇒ 3 |
długość :: Integral b => [a] -> b długość [] = 0 długość (_:t) = (+) 1 (długość t)
4.1.2 suma
Zdefiniować funkcję, która zwraca sumę wszystkich elementów listy (dla listy pustej - 0).
suma [] |
⇒ 0 |
suma [1,2,3,4,5] |
⇒ 15 |
suma :: Num a => [a] -> a suma [] = 0 suma (h:t) = (+) h (suma t)
4.1.3 sumaLog
Zdefiniować funkcję, która zwraca sumę logiczną wszystkich elementów listy typu [Bool].
sumaLog [] |
⇒ False |
sumaLog [True,False,True] |
⇒ True |
sumaLog [False,False] |
⇒ False |
4.1.4 maxB
Zdefiniować funkcję, która zwraca najwięjszy element listy. Jeśli lista jest pusta, zwraca najmniejszą wartość należącą do danego typu. Funkcja działa tylko dla list, których wartości są typu należącego do klasy Bounded.
4.1.5 następne
Zdefiniować funkcję, która bierze jako argument listę i przekształca ją w ten sposób, że każdy element zastępuje jego następnikiem.
nastepne [1,2,4,8] |
⇒ [2,3,5,9] |
nastepne "Ala ma kota." |
⇒ "Bmb!nb!lpub/" |
następne :: Enum a => [a] -> [a] następne [] = [] następne (x:xs) = succ x : następne xs
4.1.6 parzyste
Zdefiniować funkcję, która bierze jako argument listę liczb i
przekształca ją w ten sposób, że każdy element zastępuje wartością
True
, jeśli jest to liczba parzysta, wartością False
, jeśli
nie.
parzyste [1,2,3,4] |
⇒ [False,True,False,True] |
===============================
2
5 Funkcje wyższych rzędów I
5.1 mapowanie
Zdefiniować funkcję mapowanie
, będącą uogólnieniem funkcji
następne
i parzyste
. Funkcja mapowanie
bierze dwa argumenty:
funkcję, którą ma zastosować do przekształcania elementów i listę
elementów do przekształcenia.
mapowanie signum [-2,-1,0,1,2] |
⇒ [-1,-1,0,1,1] |
mapowanie null [[],[2,3],[]] |
⇒ [True,False,True] |
mapowanie :: (a -> b) -> [a] -> [b] mapowanie _ [] = [] mapowanie f (x:xs) = f x : mapowanie f xs następne' :: Enum a => [a] -> [a] następne' = mapowanie succ
5.1.1 następne'
Z wykorzystaniem funkcji mapowanie
, zdefiniować funkcję
następne'
, która działa tak samo, jak funkcja następne
.
- rozwiązanie
mapowanie = map -- biorę gotowe następne' l = mapowanie succ l
Zwróćmy uwagę:
mapowanie = map -- biorę gotowe (następne') l = (mapowanie succ) l
Widać, że
następne'
musi być równemapowanie succ
. Możemy więc definicję skrócić, pomijając zmiennąl
.mapowanie = map -- biorę gotowe następne' :: (Enum a) => [a] -> [a] następne' = mapowanie succ
5.1.2 parzyste'
Z wykorzystaniem funkcji mapowanie
, zdefiniować funkcję
parzyste'
, która działa tak samo, jak funkcja parzyste
.
5.2 redukcja
Zdefiniować funkcję redukcja
, będącą uogólnieniem funkcji
długość
, suma
, sumaLog
i maxB
. Funkcja redukcja
bierze
trzy argumenty:
- funkcję, którą ma zastosować na aktualnej wartości i wyniku rekurencyjnego zastosowania siebie na reszcie listy;
- wartość, od której zaczyna, tzn. wartość dla pustej listy;
- listę na której ma wykonać rekurencyjne obliczenie.
Np. sumę elementów listy (przyjmując, że dla listy pustej zwracamy 0) oraz długość listy powinniśmy móc obliczyć tak:
redukcja (+) 0 [1,2,3,4,5] |
⇒ 15 |
redukcja (\_ n -> n+1) 0 [1,2,3,4,5] |
⇒ 5 |
redukcja :: a -> (b -> a -> a) -> [b] -> a redukcja s _ [] = s redukcja s f (x:xs) = f x (redukcja s f xs)
redukcja :: (a -> b -> b) -> b -> [a] -> b redukcja f s [] = s redukcja f s (x:xs) = f x (redukcja f s xs)
5.2.1 długość'
Z wykorzystaniem funkcji redukcja
, zdefiniować funkcję
długość'
, która działa tak samo, jak funkcja długość
.
5.2.2 suma'
Z wykorzystaniem funkcji redukcja
, zdefiniować funkcję
suma'
, która działa tak samo, jak funkcja suma
.
redukcja :: (a -> b -> b) -> b -> [a] -> b redukcja f x [] = x redukcja f x (h:t) = f h (redukcja f x t) suma' :: Num a => [a] -> a suma' = redukcja (+) 0 długość' = redukcja (const (+ 1)) 0
5.2.3 sumaLog'
Z wykorzystaniem funkcji redukcja
, zdefiniować funkcję
sumaLog'
, która działa tak samo, jak funkcja sumaLog
.
5.2.4 iloczynLog'
Z wykorzystaniem funkcji redukcja
, zdefiniować funkcję
iloczynLog'
.
5.2.5 maxB'
Z wykorzystaniem funkcji redukcja
, zdefiniować funkcję
maxB'
, która działa tak samo, jak funkcja maxB
.
6 Złożenie funkcji
6.1 Przykład
- ↓
maParzystąDługość :: [a] -> Bool maParzystąDługość l = even (length l)
maParzystąDługość [1,2,3]
maParzystąDługość [1,2,3,4]
- ↓
maParzystąDługość' :: [a] -> Bool maParzystąDługość' l = (even . length) l
maParzystąDługość' [1,2,3]
maParzystąDługość' [1,2,3,4]
- ↓
maParzystąDługość'' :: [a] -> Bool maParzystąDługość'' = even . length
maParzystąDługość'' [1,2,3]
maParzystąDługość'' [1,2,3,4]
6.2 wszystkieParzyste
Zaimplementować funkcję "wszystkieParzyste", sprawdzającą, czy
wszystkie elementy listy są parzyste, z wykorzystaniem funkcji
parzyste'
i iloczynLog'
(poprzez złożenie).
wszystkieParzyste [1,2,3,4,5] |
⇒ False |
wszystkieParzyste [2,4] |
⇒ True |
6.3 wyrażenia funkcyjne
Podać wyrażenie, którego wartością będzie funkcja obliczająca dla podanego argumentu
- wartość
Bool
mówiącą, czy kwadrat argumentu jest większy od 10 - pierwiastek kwadratowy (sqrt) z jego kwadratu
(operator potęgowania rzeczywistego to
**
).
Sprawdzić w ghci
, czy zbudowane wyrażenia "działają".
6.4 Implementacja złożenia funkcji
Zdefiniować funkcję compose
, która działa tak, jak operator
złożenia funkcji .
i ma ten sam typ.
7 Inne
7.1 funkcjastała
Zdefiniować funkcję funkcjastała
, która dla podanego argumentu a
zwraca funkcję jednoargumentową, która niezależnie od tego, jaki
argument dostanie, zawsze zwraca wartość a.
f = funkcjastała 5 |
|
f 100 |
⇒ 5 |
f "jajko" |
⇒ 5 |
Po co komu taka funkcja?
W Haskellu taka funkcja nazywa się const
. Możemy jej użyć np. tak:
- →
let długość'' = foldr (const succ) 0
Czy to prostsza definicja niż ta w przykładzie powyżej? Dla
przypomnienia (tam zamiast foldr
było redukcja
, a zamiast succ
było (1 +)
):
- →
let długość' = foldr (\_ n -> succ n) 0
7.2 odwróć
Zdefiniować funkcję odwróć
, która dla podanej funkcji f, zwraca
funnkcje, która różni się od f tylko tym, że kolejność pierwszych
dwóch argumentów jest odwrócona.
take' = odwróć take |
|
take' [1,2,3,4,5] 3 |
⇒ [1,2,3] |
pieost :: [a] -> [a] pieost [] = [] pieost [x] = [x] pieost (h:t) = (last t : init t) ++ [h]
8 W PRZYGOTOTOWANIU
9 Lista
Definiujemy nowy typ - typ list elementów typu a:
- →
data Lista a = Cons a (Lista a) | Nil
9.1 Zdefiniować funkcje:
czyPusta::Lista a -> Bool
złącż::Lista a - > Lista a -> Lista a
redukujL::(a -> b -> b) -> b -> Lista a -> b
9.2 Uczynić typ Lista a
instancją klas:
Eq
Ord
Show
10 Drzewo
Zaprojektować typ Drzewo a
- drzewo binarne przechowujące wartości
typu a
.
10.1 Zdefiniować funkcje:
czyPuste::Drzewo a -> Bool
głębokość::Drzewo a - > Int
mapD
redukcjaD::(a -> b -> b) -> b -> Drzewo a -> b
10.2 Uczynić typ Drzewo a
instancją klas:
Eq
Show
(powinno wyświetlać się tak, żeby było widać jego strukturę)
10.3 Drzewo
z gwiazdką
Czy można jakoś zrobić, żeby nie było trzeba definiować funkcji
redukcjaD
dla naszego drzewa, ale żeby wykorzystać istniejącą
funkcję foldr
? Czyli: jak "nauczyć" funkcję foldr
przechodzenia po
naszym drzewie?