ϵ">]>
9. CVIČENIE Z PREDMETU ÚVOD DO DEKLARATÍVNEHO PROGRAMOVANIA LS 2014/2015
ČASŤ A
http://dai.fmph.uniba.sk/courses/udp/ex/ex09.zip
Dátum: 29. 4. 2015
Odporúčaná verzia CL: 5.81.21
WWW stránka predmetu: http://dai.fmph.uniba.sk/courses/udp/
Kontakt: udp(zavináč)lists.dai.fmph.uniba.sk
Literatúra.
[1] J. Kľuka. Prednášky z Úvodu do deklaratívneho programovania LS 2014/2015.
http://dai.fmph.uniba.sk/courses/udp/udp-prednasky-2015.pdf
[2] D. Guller. Poznámky k prednáškam z CL.
[3] J. Komara and P. J. Voda. Metamathematics of Computer Programming. 2001.
Definícia. Aritmetickým výrazom s premennými (skrátene aritmetickým výrazom alebo len výrazom) je:
číselná konštanta , , , …, , …,
premenná , , , …, , …,
súčtový výraz , ak a sú aritmetickými výrazmi,
súčinový výraz , ak a sú aritmetickými výrazmi.
Nič iné nie je aritmetickým výrazom.
Kódovanie aritmetických výrazov s premennými. Aritmetické výrazy majú stromovú štruktúru. Môžeme ich zakódovať podobne ako binárne stromy. Použijeme nasledujúce konštruktory:
kóduje číselnú konštantu ,
kóduje premennú ,
kóduje súčtový výraz, ktorého podvýrazy sú zakódované číslami a ,
kóduje súčinový výraz, ktorého podvýrazy sú zakódované číslami a .
Predikát platí, ak je kódom aritmetického výrazu.
Úloha. Vypočítajte hodnotu výrazov s kódmi a , ak premenná má hodnotu , premenná má hodnotu a premenná má hodnotu .
Úloha. Zjednodušte výraz s kódom tak, že súčet konštánt nahradíte jedinou konštantou. Zapíšte kód zjednodušeného výrazu pomocou konštruktorov , , , do nasledujúceho komponentu.
Úloha. Veľkosť výrazu. Zadefinujte funkciu , ktorej hodnotou je veľkosť výrazu s kódom , teda počet uzlov jeho aritmetického stromu, čiže počet aplikácií konštruktorov potrebných na jeho zakódovanie.
Testovanie:
Sz_test = rs:Results
Úloha. Premenné výrazu. Zadefinujte funkciu , ktorej hodnotou je zoznam indexov premenných vyskytujúcich sa vo výraze v poradí zľava doprava aj s prípadnými opakovaniami.
Testovanie:
Vars_test = rs:Results
Definícia. Ohodnotením (valuáciou) premenných nazveme ľubovoľný zoznam.
Hodnotou premennej pri ohodnotení je číslo (-ý prvok zoznamu ).
(Funkcia () je definovaná v module .)
Úloha. Zadefinujte denotačnú funkciu , ktorá vypočíta hodnotu aritmetického výrazu pri ohodnotení premenných .
Testovanie:
Den_test = rss:Results_den
Úloha. Výpočtami pri rôznych ohodnoteniach otestujte, či ste správne určili :
3,5,7,0 = vs & Den(Term1,vs) = dt1 & Den(Term11,vs) = dt11
a :
7 = n & n,0 = vs & Den(Term3,vs) = dt3 & n*(n+1) = dt31
Pomocou denotačnej funkcie môžeme presnejšie vyjadriť požadované vlastnosti výrazov a :
Definícia. Súčinový výraz je aritmetický výraz tvorený iba konštantami, premennými a násobením.
Tento pojem na kódoch výrazov formálne vyjadruje nasledujúci predikát .
Definícia. Aritmetický výraz je v súčtovom normálnom tvare práve vtedy, keď je súčinovým výrazom, alebo súčtom výrazov v súčtovom normálnom tvare.
Tento pojem na kódoch výrazov formálne vyjadruje nasledujúci predikát .
Poznámka. Všimnite si, že súčinové výrazy aj výrazy v súčtovom normálnom tvare sú určite výrazmi:
Prevod do súčtového normálneho tvaru. Cieľom nasledujúcich úloh je naprogramovať funkciu , ktorá ľubovoľný výraz prevedie do súčtového normálneho tvaru.
Ako sme videli na prednáške [1, §16.2.1, str. 109], na tento prevod potrebujeme pomocnú funkciu , ktorá „roznásobí“ dva výrazy v súčtovom normálnom tvare (zátvorkovanie nie je dôležité)
teda skonštruuje súčet všetkých možných súčinov . Tento výraz bude v súčtovom normálnom tvare a jeho denotácia bude rovnaká ako denotácia .
Keďže chceme vynásobiť každý súčinový podvýraz v s každým súčinovým podvýrazom v , vo funkcii budeme prechádzať iba výrazom . Keď narazíme na niektorý súčinový podvýraz , zavoláme pomocnú funkciu . Tá prejde výrazom a vynásobí jeden podvýraz každým súčinovým podvýrazom v .
V imperatívnom jazyku by sme tento postup naprogramovali dvoma vnorenými cyklami. V deklaratívnom jazyku použijeme dve vnorené rekurzívne funkcie.
Úloha. Naprogramujte funkciu spĺňajúcu špecifikáciu:
Návod. Predpokladajte (ale netestujte), že je súčinový výraz a je výraz v súčtovom normálnom tvare, teda napríklad
pre nejaké súčinové výrazy , …, (premenné, konštanty, súčiny). Hodnotou je potom súčet súčinov výrazu s každým súčinovým podvýrazom v , čiže v našom prípade
Tento výraz je v súčtovom normálnom tvare.
Testovanie.
Mul_ma_test = rs:Results_mul
Poznámka. Test tentoraz nepredpisuje presne požadovaný tvar výsledku, ale kontroluje platnosť a rovnosť denotácií na konkrétnych hodnotách a . Test závisí od správnosti funkcie .
Úloha. Naprogramujte funkciu spĺňajúcu špecifikáciu:
Návod. Predpokladajte, že a sú výrazy v súčtovom normálnom tvare, teda napríklad
pre nejaké súčinové výrazy , …, , , …, . Hodnotou je potom súčet výrazov, z ktorých každý je súčtom súčinov niektorého súčinového podvýrazu vo výraze s každým súčinovým podvýrazom v . Tieto vnútorné výrazy skonštruuje funkcia , čiže
Skonštruovaný výraz je v súčtovom normálnom tvare.
Testovanie.
Mul_aa_test = rs:Results_mul
Úloha. Naprogramujte funkciu spĺňajúcu špecifikáciu:
Návod. Funkciu stačí naprogramovať jednoduchou štrukturálnou rekurziou na výrazoch. Do súčtového normálneho tvaru prevedieme podvýrazy, ktoré potom spojíme do výrazu v súčtovom normálnom tvare. V prípade súčtu je spojenie triviálne, v prípade súčinu využite predchádzajúce funkcie.
Testovanie.
Anf_from_test = rs:Results_anf
Definícia. Výraz s doľava asociovaným sčítaním je aritmetický výraz, v ktorom pravý argument žiadneho sčítania (ktoré nie je potomkom násobenia) nie je sčítanie.
Tento pojem na kódoch výrazov formálne vyjadruje nasledujúci predikát .
Úloha. Všimnite si, že hodnota, ktorá vyhovuje predikátu nemusí byť nutne výrazom, teda
(na rozdiel od predikátov a vyššie).
Zapíšte takú hodnotu do nasledujúcej konštanty .
Testovanie.
Lassoc_not_term = t & Lassoc(t) & ~Term(t)
Úloha. Naprogramujte funkciu , ktorá vráti výraz s doľava asociovaným sčítaním, ktorého veľkosť a hodnoty pri všetkých ohodnoteniach premenných sú rovnaké ako pre výraz .
Návod. Transformácia výrazu , kde , …, nie sú súčty, by mala prebehnúť v nasledujúcich krokoch:
.
Testovanie.
Lassoc_from_test = rs:Results_lassoc
Poznámka. Test tentoraz nepredpisuje presne požadovaný tvar výsledku, ale kontroluje splnenie jednotlivých bodov špecifikácie (platnosť , rovnosť denotácií a veľkostí) na konkrétnych hodnotách a . Test závisí od správnosti funkcie .
Prémiová domáca úloha du09. (2 body)
Pravidlá pre prémiové domáce úlohy nájdete na http://dai.fmph.uniba.sk/courses/udp/#pdu.
Termín odovzdania: nedeľa 10. 5. 2015 23:59:59
Zadanie. Zadefinujte funkciu , ktorá za každý výskyt premennej vo výraze dosadí výraz .
Špecifikácia.
Príklady.
Testovanie.
Subst_test = r:Results_subst