|
Funkce na seznamech II
map
map je binární funkce, která si jako argumenty bere:
- unární funkci
f , která z a dělá b
- seznam
s typu [a] , na jehož prvky se dá aplikovat funkce f
Výraz map f s se vyhodnotí na seznam s , na jehož každý prvek je aplikována funkce f , typu [b] .
Definice
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:s) = f x : map f s
Příklady
map (+1) [1,2,3] ~>* [2,3,4]
map even [1,2,3] ~>* [False, True, False]
map (*8) [] ~>* []
Příklad vyhodnocení
Teď nastává ten okamžik, kdy využijeme přirovnání seznamu k vláčku. Pokud si seznam představíme jako vláček, pak funkce map je tunel.
Vláčkový model
| Haskell
|
Mějme funkci naloz , která dělá to, že na prázdný vagónek naloží uhlí a plný vagónek nechá plný.
|
Mějme funkci naloz , která je definována následovně:
naloz :: Bool -> Bool
naloz False = True
naloz True = True
|
Tunel se chová následovně:
- Pokud je v něm vagónek, naloží na něj uhlí a posune vláček.
- Pokud je v něm mašinka, nechá ji projet a ukončí svou činnost.
| Funkce map se chová následovně:
- Pokud je aplikována na funkci
f a neprázdný seznam x:s , na první prvek seznamu, čili na x , aplikuje funkci f , výsledek připojí na začátek výsledného seznamu a pokračuje aplikací funkce map na zbytek seznamu s .
- Pokud je aplikována na libovolnou funkci a prázdný seznam, vyhodnotí se na prázdný seznam.
|
Pošleme tedy do tunelu, který nakládá uhlí, vláček, který má tři prázdné vagónky.
|
Aplikujme tedy funkci map na funkci naloz a na seznam [False,False,False] .
|
|
V tunelu je prázdný vagónek, takže se na něj naloží uhlí a vláček se posune.
|
Jelikož je druhým argumentem neprázdný seznam, vyhodnocujeme podle druhé klauzule funkce map . Aplikujeme funkci naloz na první prvek seznamu, což je False . Tím nám vznikne True , které připojíme na začátek a pokračujeme vyhodnocováním map naloz [False,False] .
|
|
V tunelu je prázdný vagónek, takže se na něj naloží uhlí a vláček se posune.
|
Opět vyhodnocujeme podle druhé klauzule. Za x se dosadí False , za s se dosadí [False] . Na začátek se tedy připojí naloz False , což se vyhodnotí na True , a pokračuje se vyhodnocováním map naloz [False] .
|
|
Stejná situace, naloží se uhlí a posune se vláček.
|
Opět podle druhé klauzule: Za x se dosadí False , za s se dosadí [] , čili vyhodnocení vypadá následovně:
map naloz (False : [])
~> (naloz False) : map naloz []
|
|
V tunelu je mašinka, která jen projede, a jsme hotovi.
|
Výraz map naloz [] se vyhodnotí podle první klauzule na prázdný seznam.
|
|
Výsledkem je vláček se třemi naloženými vagónky.
|
Výsledkem je tříprvkový seznam [True,True,True] .
|
filter
filter je binární funkce. Jejími argumenty jsou:
-
podmínka
p , což je funkce, která z čehokoli udělá pravdivostní hodnotu, její typ je tedy a -> Bool
-
seznam
s , jehož prvky se dají vložit do funkce p , typ tohoto seznamu je [a]
Výraz filter p s se vyhodnotí na seznam, jehož prvky budou prvky seznamu s , které vyhovují podmínce p .
Definice
filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter p (x:s) = if p x then x : filter p s
else filter p s
Příklady
filter (>5) [1,6,2,8,5,7] ~>* [6,8,7]
filter even [1,6,2,8,5,7] ~>* [6,2,8]
filter not [False,True,False] ~>* [False,False]
Příklad vyhodnocení
Funkci filter můžeme, jako funkci map , znázornit tunelem. Bude se ale chovat trochu jinak.
Vláčkový model
| Haskell
|
Mějme funkci jePlny , která zjišťuje, zda je vagónek do ní vložený naložený uhlím.
|
Mějme funkci jePlny , která je definována následovně:
jePlny :: Bool -> Bool
jePlny True = True
jePlny False = False
nebo zkráceně
jePlny :: Bool -> Bool
jePlny x = x
nebo ještě kratčeji
jePlny :: Bool -> Bool
jePlny = id
|
Tunel se chová následovně:
-
Pokud funkce
jePlny zjistí, že vagónek v tunelu je naložen uhlím, pustí jej z tunelu a posune vláček.
-
Pokud funkce
jePlny zjistí, že vagónek v tunelu je prázdný, vagónek zahodí a posune vláček.
|
Funkce filter se chová následovně:
-
Pokud je aplikována na funkci
p a neprázdný seznam x:s , postupuje se následovně:
-
Pokud se aplikace
p x vyhodnotí na True , připojí se prvek x na začátek výsledného seznamu a dále se vyhodnocuje výraz filter p s .
-
Pokud se aplikace
p x vyhodnotí na False , prvek x se zahodí a rovnou se vyhodnocuje filter p s .
-
Pokud je aplikována na jakoukoli funkci a prázdný seznam, vyhodnotí se na prázdný seznam.
|
Do tunelu, který vybírá pouze naložené vagónky, tedy pošleme třívagónkový vláček s vagónky: naložený, prázdný, naložený.
|
Aplikujme tedy funkci filter na funkci jePlny a seznam [True,False,True] .
|
|
V tunelu je naložený vagónek, který tím pádem chceme ponechat i ve výsledném vláčku. Takže se tento vagónek dostane z tunelu a posune se vláček.
|
Druhým argumentem je neprázdný seznam, vyhodnocuje se podle druhé klauzule. Aplikace funkce p na x , po dosazení jePlny True , se vyhodnotí na True . if -výraz se tedy vyhodnotí na then -větev, což je x : filter p s . Po dosazení True : filter jePlny [False,True] .
|
|
Nyní je v tunelu prázdný vagónek, který ve výsledném vláčku nechceme. Takže jej zahodíme a posuneme vláček.
|
Opět je druhým argumentem neprázdný seznam, vyhodnocuje se podle druhé klauzule. Protože se výraz jePlny False vyhodnotí na False , if -výraz se vyhodnotí na else -větev, čili na výraz filter jePlny [True] .
|
|
V tunelu je naložený vagónek, takže jej pošleme dál a posuneme vláček.
|
Opět se vyhodnocuje podle druhé klauzule. Tentokrát je podmínka p splněna, takže se if -výraz vyhodnotí na then -větev, čili na výraz True : filter jePlny [] .
|
|
V tunelu je mašinka, kterou necháme projet a jsme hotovi.
|
Druhým argumentem je prázdný seznam, takže vyhodnocujeme podle první klauzule na prázdný seznam.
|
|
Výsledkem je vláček se dvěma naloženými vagónky.
|
Výsledkem je dvojprvkový seznam [True,True] .
|
take
Popis
Funkce take x s vrátí seznam prvních x prvků ze seznamu s .
Definice
Poznámka: Zde uvedená definice je zjednodušená. Ve skutečnosti může take jako první argument přijmout i záporné číslo. V takovém případě se vyhodnotí na prázdný seznam.
take 0 _ = []
take _ [] = []
take n (x:s) = x : take (n-1) s
Příklady
take 3 [1,2,3,4,5] ~>* [1,2,3]
take 4 "Ahoj ty tam!" ~>* "Ahoj"
take 0 [True, True] ~>* []
take 5 [] ~>* []
drop
Výraz drop n s se vyhodnotí na seznam s bez prvních n prvků.
Definice
drop 0 s = s
drop _ [] = []
drop n (_:s) = drop (n-1) s
Poznámka: Stejně jako u funkce take je i tato definice zjednodušená. Funkce drop může jako první parametr přijmout i záporné číslo. V tom případě vrátí celý seznam v druhém argumentu.
Příklady
drop 2 [1,2,3,4,5] ~>* [3,4,5]
drop 0 [1,2,3,4,5] ~>* [1,2,3,4,5]
drop 8 [True, False] ~>* []
repeat
Funkce repeat x vytvoří nekonečný seznam x .
[x,x,x,x,x,x,x, ... ]
Definice
repeat :: a -> [a]
repeat x = x : repeat x
Příklady
repeat 1 ~>* [1,1,1,1,1, ... ]
repeat 'c' ~>* "ccccccccc ... "
repeat [True, False] ~>* [[True, False],[True, False], ... ]
Poznámka
Pokud si necháme vyhodnotit například výraz repeat 1 , Hugs začne do nekonečna vypisovat seznam jedniček, dokud jej nezastavíme kombinací kláves Ctrl+C.
replicate
replicate n x vytvoří n -prvkový seznam x -ů.
Definice
replicate :: Int -> a -> [a]
replicate n x = take n (repeat x)
Příklady
replicate 4 1 ~>* [1,1,1,1]
replicate 3 "Haskell" ~>* ["Haskell","Haskell","Haskell"]
replicate 10 'c' ~>* "cccccccccc"
|