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
  1. rozwiązanie
    ileRazyPrzez :: Integral a => a -> a -> Int
    ileRazyPrzez n k | n < k     = 0
                     | otherwise = 1 + ileRazyPrzez (n `div` k) k         
    
    • ileRazyPrzez 7 8
    • ileRazyPrzez 27 3
    • ileRazyPrzez 1024 2

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.

  1. rozwiązanie
    maxB :: (Bounded a, Ord a) => [a] -> a
    maxB []    = minBound
    maxB (h:t) = max h (maxB t)
    
    • maxB []::Int
    • maxB [1,2,3,4,5]::Int

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.

  1. 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ówne mapowanie 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

  1. wartość Bool mówiącą, czy kwadrat argumentu jest większy od 10
  2. 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:

  1. czyPusta::Lista a -> Bool
  2. złącż::Lista a - > Lista a -> Lista a
  3. redukujL::(a -> b -> b) -> b -> Lista a -> b

9.2 Uczynić typ Lista a instancją klas:

  1. Eq
  2. Ord
  3. Show

10 Drzewo

Zaprojektować typ Drzewo a - drzewo binarne przechowujące wartości typu a.

10.1 Zdefiniować funkcje:

  1. czyPuste::Drzewo a -> Bool
  2. głębokość::Drzewo a - > Int
  3. mapD
  4. redukcjaD::(a -> b -> b) -> b -> Drzewo a -> b

10.2 Uczynić typ Drzewo a instancją klas:

  1. Eq
  2. 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?

11 Muzyka

Author: Tomasz Obrębski

Created: 2019-03-22 pią 14:53

Validate