IB015 Neimperativní programování. Seznamy, Typy a Rekurze. Jiří Barnat Libor Škarvada

Podobné dokumenty
IB015 Neimperativní programování. Organizace a motivace kurzu, programovací jazyk Haskell. Jiří Barnat

Programovací í jazyk Haskell

Programovací jazyk Haskell

IB015 Neimperativní programování. Časová složitost, Typové třídy, Moduly. Jiří Barnat Libor Škarvada

IB015 Neimperativní programování. Redukční strategie, Seznamy program QuickCheck. Jiří Barnat Libor Škarvada

Definice uživatelského typu. Uživatelem definované typy. Součinové datové typy. Součtové datové typy. FLP - Uživatelem definované typy

Haskell Hero učební text

Funkcionální programování. Kristýna Kaslová

Algoritmizace a programování

Inovace a zkvalitnění výuky prostřednictvím ICT Základy programování a algoritmizace úloh. Ing. Hodál Jaroslav, Ph.D. VY_32_INOVACE_25 09

Martin Milata, Pokud je alespoň jeden rozměr čokolády sudý (s výjimkou tabulky velikosti 1x2, která už je od

Programovací jazyk Pascal

Operátory, výrazy. Tomáš Pitner, upravil Marek Šabo

Pascal. Katedra aplikované kybernetiky. Ing. Miroslav Vavroušek. Verze 7

5 Přehled operátorů, příkazy, přetypování

Úvod do programování. Lekce 1

Logické operace. Datový typ bool. Relační operátory. Logické operátory. IAJCE Přednáška č. 3. může nabýt hodnot: o true o false

2 Strukturované datové typy Pole Záznam Množina... 4

Lokální definice (1) plocha-kruhu

8 Třídy, objekty, metody, předávání argumentů metod

Zápis programu v jazyce C#

Booleovská algebra. Booleovské binární a unární funkce. Základní zákony.

Výrazy a operátory. Operátory Unární - unární a unární + Např.: a +b

Obsah přednášky. programovacího jazyka. Motivace. Princip denotační sémantiky Sémantické funkce Výrazy Příkazy Vstup a výstup Kontinuace Program

Algoritmizace prostorových úloh

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

Přednáška 7. Celočíselná aritmetika. Návratový kód. Příkazy pro větvení výpočtu. Cykly. Předčasné ukončení cyklu.

Algoritmizace a programování

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Úvod do programovacích jazyků (Java)

Úvod do jazyka C. Ing. Jan Fikejz (KST, FEI) Fakulta elektrotechniky a informatiky Katedra softwarových technologií

for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }

- speciální symboly + - * / =., < > <> <= >= a další. Klíčová slova jsou chráněnými útvary, které nelze použít ve významu identifikátorů.

Základní pojmy. Úvod do programování. Základní pojmy. Zápis algoritmu. Výraz. Základní pojmy

SPJA, cvičení 1. ipython, python, skripty. základy syntaxe: základní datové typy, řetězce. podmínky: if-elif-else, vyhodnocení logických výrazů

Úvod do programovacích jazyků (Java)

2 Datové typy v jazyce C

Proměnná. Datový typ. IAJCE Cvičení č. 3. Pojmenované místo v paměti sloužící pro uložení hodnoty.

Motivace. Vstup a výstup. Minimální komunikace. Motivace. ÚDPJ - Vstup a výstup. Ing. Lumír Návrat katedra informatiky, A

- znakové konstanty v apostrofech, např. a, +, (znak mezera) - proměnná zabírá 1 byte, obsahuje kód příslušného znaku

LEKCE 6. Operátory. V této lekci najdete:

Operátory. Základy programování 1 Martin Kauer (Tomáš Kühr)

Martin Flusser. Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague. October 17, 2016

IV113 Validace a verifikace. Převod LTL formule na Büchi automat. Jiří Barnat

Poslední nenulová číslice faktoriálu

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

3 Množiny, Relace a Funkce

PARADIGMATA PROGRAMOVÁNÍ 2 PŘÍSLIBY A LÍNÉ VYHODNOCOVÁNÍ

Sémantika výrokové logiky. Alena Gollová Výroková logika 1/23

Čtvrtek 8. prosince. Pascal - opakování základů. Struktura programu:

Programování v jazyce JavaScript

Paměť počítače. alg2 1

PŘETĚŽOVÁNÍ OPERÁTORŮ

Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

C++ Akademie SH. 2. Prom nné, podmínky, cykly, funkce, rekurze, operátory. Michal Kvasni ka. 20. b ezna Za áte níci C++

Jazyk C Program v jazyku C má následující strukturu: konstanty nebo proměnné musí Jednoduché datové typy: Strukturované datové typy Výrazy operátory

Rekurze. Pavel Töpfer, 2017 Programování 1-8 1

LabView jako programovací jazyk II

Algoritmizace prostorových úloh

Test prvočíselnosti. Úkol: otestovat dané číslo N, zda je prvočíslem

Jak v Javě primitivní datové typy a jejich reprezentace. BD6B36PJV 002 Fakulta elektrotechnická České vysoké učení technické

Vyučovací hodina. 1vyučovací hodina: 2vyučovací hodiny: Opakování z minulé hodiny. Procvičení nové látky

PODPROGRAMY PROCEDURY A FUNKCE

1.1 Struktura programu v Pascalu Vstup a výstup Operátory a některé matematické funkce 5

Slepé prohledávání do šířky Algoritmus prohledávání do šířky Při tomto způsobu prohledávání máme jistotu, že vždy nalezneme koncový stav, musíme ale p

Sada 1 - PHP. 03. Proměnné, konstanty

SII - Informatika. 1. Atribut relace, jehož hodnota jednoznačně určuje prvek v jiné relaci, se nazývá:

EVROPSKÝ SOCIÁLNÍ FOND. Úvod do PHP PRAHA & EU INVESTUJEME DO VAŠÍ BUDOUCNOSTI

Obsah. Úvod 11 Základy programování 11 Objektový přístup 11 Procvičování 11 Zvláštní odstavce 12 Zpětná vazba od čtenářů 12 Errata 13

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Operátory. Základy programování 1 Tomáš Kühr

Prolog PROgramming in LOGic část predikátové logiky prvního řádu rozvoj začíná po roce 1970 Robert Kowalski teoretické základy Alain Colmerauer, David

Implementace LL(1) překladů

Algoritmizace a programování. Ak. rok 2012/2013 vbp 1. ze 44

dovolují dělení velkých úloh na menší = dekompozice

Dynamicky vázané metody. Pozdní vazba, virtuální metody

teorie logických spojek chápaných jako pravdivostní funkce

Software602 Form Designer

Functional and Logic Programming Functional languages

Základy programování (IZP)

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Standardní algoritmy vyhledávací.

NPRG030 Programování I, 2017/18 1 / :22:16

Algoritmizace prostorových úloh

Program převod z desítkové na dvojkovou soustavu: /* Prevod desitkove na binarni */ #include <stdio.h>

Booleovská algebra. Pravdivostní tabulka. Karnaughova mapa. Booleovské n-krychle. Základní zákony. Unární a binární funkce. Podmínky.

Sada 1 - Základy programování

Paradigmata programování 1

Programování v jazyce C pro chemiky (C2160) 3. Příkaz switch, příkaz cyklu for, operátory ++ a --, pole

První kapitola úvod do problematiky

III/2 Inovace a zkvalitnění výuky prostřednictvím ICT

Logické programování I

7. Datové typy v Javě

Datové struktury. Obsah přednášky: Definice pojmů. Abstraktní datové typy a jejich implementace. Algoritmizace (Y36ALG), Šumperk - 12.

Jazyk C# a platforma.net

Objektově orientované programování

Výroková a predikátová logika - II

C# konzole Podíl dvou čísel, podmínka IF

Transkript:

IB015 Neimperativní programování Seznamy, Typy a Rekurze Jiří Barnat Libor Škarvada

Sekce IB015 Neimperativní programování 02 str. 2/36 Uspořádané n-tice a seznamy

Programování a data IB015 Neimperativní programování 02 str. 3/36 Pozorování Programy pro své fungování potřebují různé informace data. Data jsou vstupní hodnoty, výstupní hodnoty, mezivýsledky výpočtů, parametry funkcí, atd. Programování a data Data je třeba uchovávat tak, aby je bylo možné zpracovat mechanicky/strojově. Tvorba jednoznačného popisu struktury a způsobu uložení dat je nedílná součást procesu programování. Pro uchování informací používáme různé datové struktury.

Strukturovaná data IB015 Neimperativní programování 02 str. 4/36 Dekompozice dat Veškerá data použitá v programu je třeba vystavět ze základních datových elementů podle definovaných pravidel. Existují striktní pravidla pro dekompozici dat, my si však v rámci IB015 vystačíme s intuicí. Základní datové elementy Čísla, Znaky, Pravdivostní hodnoty Základní způsoby kompozice dat Uspořádané n-tice Seznamy

Uspořádané n-tice IB015 Neimperativní programování 02 str. 5/36 Co to je Příklady Pevně daný počet nějakých hodnot v pevně daném pořadí. Prvek kartézského součinu nosných množin. Datum: (11, "březen", 1977). Přihlašovací údaje: ("xbarnat", "majen10cm") Pozice pixelu v rastrovém obrázku: (x, y), všimněme si, že (12,43) (43,12). Kdy se má použít Počet prvků v n-tici je znám předem, tj. v okamžiku psaní zdrojového kódu. Počet prvků v n-tici je malý (hodnota n je malá).

Seznamy IB015 Neimperativní programování 02 str. 6/36 Co to je Posloupnost hodnot stejného charakteru (stejného typu). Posloupnost může být prázdná, konečná i nekonečná. Každý prvek v seznamu je na nějaké (unikátní) pozici. Příklady Seznam čísel: [12,43,-3,15,29] Nekonečný seznam: [1,2,3,4,5,6,...] Seznam uspořádaných dvojic: [("Fero",12), ("Nero",7), ("Pero",5)] Prázdný seznam: [] Kdy se má použít Data vznikají nebo se zpracovávají postupně. Počet prvků použitých programem není předem znám.

Příklad dekompozice dat IB015 Neimperativní programování 02 str. 7/36 Aplikace Diář squashových partnerů. Program pro správu kontaktů na různé squashové hráče. Hlavní datová struktura je seznam kontaktů. Datová dekompozice Seznam kontaktů [kontakt1, kontakt2, kontakt3,..., kontakt315] Kontakt je uspořádaná trojice (Prezdivka, Telefon, Adresa) Adresa je uspořádaná pětice (Jmeno, Prijmeni, Ulice, Cislo Popisne, Mesto) Prezdivka, Jmeno, Prijmeno, Ulice, Mesto jsou seznamy znaků Telefon, Cislo Popisne jsou čísla

Sekce IB015 Neimperativní programování 02 str. 8/36 Hodnoty a Typy

Co není typ Typ není váš nepřítel IB015 Neimperativní programování 02 str. 9/36

Co není typ Typ není váš nepřítel IB015 Neimperativní programování 02 str. 9/36

Co je to typ a k čemu je IB015 Neimperativní programování 02 str. 10/36 Co je to typ Označení množiny všech hodnot dané kvality. Komunikační prostředek napomáhající správnému skládání programů z jednotlivých funkcí. K čemu se používají typy Každá hodnota, nebo výraz má svůj typ. Definice typové signatury funkcí. Kontrola logické konzistence programu v době překladu. Popis způsobu kompozice složených datových struktur. (Typy se komponují stejně jako data.)

Konstrukce typů IB015 Neimperativní programování 02 str. 11/36 Základní datové typy Int, Integer, Float, Char, Bool Složené typy Uspořádané n-tice: (Bool,Int) Seznamy: [Int], [Char], [[Char]] [Char] String Funkcionální typy Integer -> Bool, Float -> Float -> Float

Funkcionální typy IB015 Neimperativní programování 02 str. 12/36 Konstrukce Jsou-li σ a τ nějaké typy, tak σ -> τ je typ všech funkcí s parametrem typu σ a funkční hodnotou typu τ. Typ n-árních funkcí Jsou-li σ 1, σ 2, σ 3... σ n a τ nějaké typy, tak σ 1 -> σ 2 -> σ 3 ->... -> σ n -> τ je typ všech funkcí s prvním parametrem typu σ 1, druhým parametrem typu σ 2,... a funkční hodnotou typu τ. Terminologie Arita funkce označuje počet parametrů funkce. Konstanty, unární, binární, ternární funkce. Nulární funkce (n=0) jsou konstanty daného typu.

Funkcionální typ a aplikace IB015 Neimperativní programování 02 str. 13/36 Pozorování Příklad Typ výrazu, který je úplná aplikace funkce na parametry, lze odvodit z typu použité funkce bez nutnosti výpočtu výsledné hodnoty. odd :: Integer -> Bool 27 :: Integer odd 27 :: Bool

Polymorfní typy IB015 Neimperativní programování 02 str. 14/36 Pozorování Příklad Některé funkce nepotřebují znát konkrétní typy formálních parametrů, pouze jejich strukturu. Místo konkrétního typu se použije typová proměnná. Při aplikaci funkce na konkrétní parametry, se za typovou proměnnou dosadí typ, který odpovídá použitému parametru. (Typová proměnná se specializuje.) POZOR! Typová proměnná zastupuje i složené typy. fst :: (a,b) -> a (not,"coze?") :: (Bool -> Bool,[Char]) fst (not,"coze?") :: Bool -> Bool

Typové třídy IB015 Neimperativní programování 02 str. 15/36 Pozorování Některé funkce nevyžadují konkrétní typ, ale zároveň nedovolují použití libovolného typu, proto je třeba specializaci typové proměnné omezit na vybranou podtřídu typů. Základní typové třídy Integral Num Ord Eq celočíselné numerické uspořadatelné porovnatelné na rovnost Příklady typů s omezením specializace typové proměnné odd :: Integral a => a -> Bool (+) :: Num a => a -> a -> a

Sekce IB015 Neimperativní programování 02 str. 16/36 Uspořádané n-tice a seznamy v Haskellu

Uspořádané n-tice v Haskellu IB015 Neimperativní programování 02 str. 17/36 Zápis uspořádaných n-tic Přirozený, pomocí závorek a čárek. Příklady zápisu uspořádaných n-tic v Haskellu: (12,15) (2,3, a,5,6) ("Fiii","jo", 350, "tisíc",! ) ((1,1),(2,2),(3,3)) Krajní případy Jednotice se nepoužívají. Nultice: ()

Předdefinované funkce pro uspořádané dvojice IB015 Neimperativní programování 02 str. 18/36 Datové konstruktory (...,) datový konstruktor uspořádané n-tice (,) datový konstruktor uspořádané dvojice (,) :: a -> b -> (a,b) (,) x y = (x,y) Projekce fst, snd projekce na první a druhou složku fst :: (a,b) -> a fst (x,y) = x snd :: (a,b) -> b snd (x,y) = y

Seznamy IB015 Neimperativní programování 02 str. 19/36 Zápis seznamů V hranatých závorkách uzavřená posloupnost prvků oddělených čárkou. Příklady Seznam znaků též jako řetězec (text v uvozovkách). [3,3,3,3] [ [1], [1,2], [1,2,3] ] [] "ahoj" = [ a, h, o, j ] "toto je také seznam" [ or, or, or, and ]

Konstrukce seznamů IB015 Neimperativní programování 02 str. 20/36 Datové konstruktory Prázdný seznam: [] [] :: [a] Operátor připojení prvku na začátek seznamu: (:) Příklady (:) :: a -> [a] -> [a] Správné použití (:) 3 [3,3,3] [3,3,3,3] 1:2:3:[] [1,2,3] 4:[4,4,4,4] [4,4,4,4,4] A :"hoj" "Ahoj" Nesprávné použití [2] : [3,4,5] ERROR [2,3,4] : 5 ERROR A : [1,2,3] ERROR

Konstrukce seznamů pokračování IB015 Neimperativní programování 02 str. 21/36 Funkce pro spojení seznamů Seznamy stejného typu lze spojit pomocí funkce (++) (++) :: [a] -> [a] -> [a] Příklady Správné použití (++) "Ahoj " "světe!" "Ahoj světe!" "Ahoj" ++ " " ++ "světe!" "Ahoj světe!" [1,2,3] ++ [4,5,6] [1,2,3,4,5,6] Nesprávné použití 2 ++ [3,4,5] ERROR [2,3,4] ++ 5 ERROR [2,3] ++ "text" ERROR

Význam datových konstruktorů IB015 Neimperativní programování 02 str. 22/36 Datové konstruktory ve víceřádkových definicích Příklady Fungují jako vzory na levých stranách definice. Mapují se vždy na nejvnějšnější výskyt. Funkce null aplikovaná na nějaký seznam, vrací True pokud je seznam prázdný a False pokud je neprázdný. null :: [a] -> Bool null (_:_) = False null [] = True Funkce snd aplikovaná na uspořádanou dvojici, vrací druhý prvek dvojice. snd :: (a,b) -> b snd (_,y) = y

Sekce IB015 Neimperativní programování 02 str. 23/36 Rekurze

Rekurze IB015 Neimperativní programování 02 str. 24/36 Co je to rekurze Definice funkce, nebo datové struktury, s využitím sebe sama. Význam v programování Umožňuje konečně dlouhý zápis definice funkce, která je definována pro nekonečně mnoho parametrů. V čistě funkcionálním jazyce nahrazuje cykly známé z imperativních programovacích jazyků. Příklad Funkci length, která při aplikaci na seznam vrací jeho délku, je nutné definovat rekurzivně. length :: [a] -> Int length [] = 0 length (_:s) = 1 + length s

Příklad výpočtu rekurzivní definice B015 Neimperativní programování 02 str. 25/36 length :: [a] -> Int length [] = 0 length (_:s) = 1 + length s length [6,7,8,9] 1 + length [7,8,9] 1 + ( 1 + length [8,9]) 1 + ( 1 + ( 1 + length [9])) 1 + ( 1 + ( 1 + ( 1 + length []))) 1 + ( 1 + ( 1 + ( 1 + 0 ))) 1 + ( 1 + ( 1 + 1 )) 1 + ( 1 + 2 ) 1 + 3 4

Další příklady použití rekurze B015 Neimperativní programování 02 str. 26/36 Číselné funkce factorial :: Integer -> Integer factorial 0 = 1 factorial x = x * factorial (x-1) Nekonečné opakování (teoreticky) main :: IO() main = do putstrln "Vloz text:" x <- getline putstrln ( "Zadal jsi:" ++ x ) main

Rekurze je mentálně náročná IB015 Neimperativní programování 02 str. 27/36 Pozorování Použití rekurze je možné pouze tehdy, je-li podproblém, na nějž se rekurzivně aplikuje dané řešení, stejného typu. Slovní úloha Na Jiříkovu narozeninovou párty přišlo 7 kamarádů a přineslo mimo jiné jeden narozeninový dort. Jiřík nebyl lakomý, rozdělil dort rovnoměrně mezi všechny přítomné. Jakou k tomu použil rekurzivní funkci? Jaký je typ této rekurzivní funkce?

Rekurze je mentálně náročná IB015 Neimperativní programování 02 str. 27/36 Pozorování Použití rekurze je možné pouze tehdy, je-li podproblém, na nějž se rekurzivně aplikuje dané řešení, stejného typu. Slovní úloha Řešení Na Jiříkovu narozeninovou párty přišlo 7 kamarádů a přineslo mimo jiné jeden narozeninový dort. Jiřík nebyl lakomý, rozdělil dort rovnoměrně mezi všechny přítomné. Jakou k tomu použil rekurzivní funkci? Jaký je typ této rekurzivní funkce? dort :: [KouskyDortu] -> [KouskyDortu] dort s = if (length s >= 8) then s else dort (map (/2) s ++ map (/2) s)

Sekce IB015 Neimperativní programování 02 str. 28/36 Práce se seznamy v Haskellu

head, tail, init, last První prvek seznamu head :: [a] -> a head (x:_) = x Seznam bez prvního prvku tail :: [a] -> [a] tail (_:s) = s head tail Poslední prvek seznamu last :: [a] -> a last (x:[]) = x last (_:s) = last s Seznam bez posledního prvku init :: [a] -> [a] init (_:[]) = [] init (x:_:[]) = [x] 1 2 3 init 4 5 6 last init (x:s) = x:init s IB015 Neimperativní programování 02 str. 29/36

null, length, (!!) B015 Neimperativní programování 02 str. 30/36 Test na prázdný seznam null :: [a] -> Bool null (_:_) = False null [] = True Délka seznamu length :: [a] -> Int length [] = 0 length (_:s) = 1 + length s N-tý prvek seznamu (!!) :: [a] -> Int -> a (x:_)!! 0 = x (_:s)!! k = s!! (k-1)

take, drop IB015 Neimperativní programování 02 str. 31/36 Prvních n prvků seznamu take :: Int -> [a] -> [a] take _ [] = [] take n (x:s) = if (n>0) then x : take (n-1) s else [] Seznam bez prvních n prvků; drop :: Int -> [a] -> [a] drop _ [] = [] drop n (x:s) = if (n>0) then drop (n-1) s else (x:s) Poznámka Při infixovém použití binární funkce klesá její priorita! x : take (n-1) s = x : (take (n-1) s)

concat, filtr, replicate IB015 Neimperativní programování 02 str. 32/36 Spojení seznamů v seznamu concat :: [[a]] -> [a] concat [] = [] concat (x:s) = x ++ concat s Vynechání prvků nesplňujících danou podmínku filter :: (a -> Bool) -> [a] -> [a] filter _ [] = [] filter f (x:s) = if (f x) then x : filter f s else filter f s Vytvoření seznamu n-násobným kopírováním daného prvku replicate :: Int -> a -> [a] replicate 0 _ = [] replicate k x = x : replicate (k-1) x

takewhile, dropwhile, map B015 Neimperativní programování 02 str. 33/36 Vynechání prvků seznamu od prvního, který nesplňuje podmínku takewhile :: (a->bool) -> [a] -> [a] takewhile _ [] = [] takewhile p (x:s) = if (p x) then x : takewhile p s else [] Vynechání prvků seznamu po první, který nesplňuje podmínku dropwhile :: (a->bool) -> [a] -> [a] dropwhile _ [] = [] dropwhile p (x:s) = if (p x) then dropwhile p s else x:s Aplikace funkce na všechny prvky seznamu map :: (a -> b) -> [a] -> [b] map _ [] = [] map f (x:s) = f x : map f s

zip,unzip B015 Neimperativní programování 02 str. 34/36 Spojení dvou seznamů do seznamu uspořádaných dvojic zip :: [a] -> [b] -> [(a,b)] zip [] _ = [] zip _ [] = [] zip (x:s) (y:t) = (x,y) : zip s t Rozdělení seznamu dvojic na dvojici seznamů unzip :: [(a,b)] -> ([a],[b]) unzip [] = ([],[]) unzip ((x,y):s) = (x : fst t, y : snd t) where t = unzip s

zipwith B015 Neimperativní programování 02 str. 35/36 Výpočet aplikace binární funkce na seznamy argumentů zipwith :: (a->b->c)->[a]->[b]->[c] zipwith [] = [] zipwith _ [] _ = [] zipwith f (x:s) (y:t) = f x y : zipwith f s t Pozorování zip = zipwith (,)

Práce na doma IB015 Neimperativní programování 02 str. 36/36 Technická cvičení Vyzkoušejte si všechny odpřednášené funkce na modelových seznamech v prostředí interpretru jazyka Haskell. Mentální cvičení Napište program, který pomocí principu rekurze a s využitím odpřednášených operací na seznamech vypočítá seznam obsahující čísla od 1 do 1024. Snažte se o to, aby hloubka rekurze byla co nejmenší. Jsou-li vám známy cykly s pevným počtem opakování z nějakého imperativního programovacího jazyka, popřemýšlejte o obecném postupu, jak nahradit tyto cykly voláním rekurzivní funkce.