120 likes | 245 Views
JUI - 4. přednáška Programové struktury, mapovací funkcionály, makra. RNDr. Jiří Dvořák, CSc. dvorak@uai.fme.vutbr.cz. Programování rekurzivních funkcí. Typické možnosti pro testování triviálních alternativ v definici a pro redukci argumentu do rekurzivního volání:
E N D
JUI - 4. přednáškaProgramové struktury, mapovací funkcionály, makra RNDr. Jiří Dvořák, CSc. dvorak@uai.fme.vutbr.cz
Programování rekurzivních funkcí • Typické možnosti pro testování triviálních alternativ v definici a pro redukci argumentu do rekurzivního volání: • Pro číselný argument testujeme rovnost nule (zerop) nebo jedné (onep), případně i zápornou hodnotu (minusp) argumentu; do rekurzivní větve dáváme zmenšenou hodnotu argumentu (typicky o hodnotu jedna pomocí sub1), obecně hodnotu bližší triviální alternativě. • Pro seznam zpracovávaný jen v nejvyšší úrovni testujeme zda seznam je prázdný (null) a argument redukujeme na cdr, případně i více. • Pro obecně strukturovaný S-výraz testujeme většinou jako zvláštní případy prázdný seznam (null) a atom (atom) – v tomto pořadí! – a argument redukujeme na car i cdr.
Rekurze a iterace • Pokud v použité implementaci Lispu neumí překladač automaticky nahradit koncovou rekurzi iterací, dochází nepochybně při rekurzivním volání funkcí ke větší spotřebě strojového času, než kolik by potřeboval odpovídající iterační algoritmus. • Dále jsme v tomto případě při výpočtu i té nejjednodušší rekurzivně definované funkce omezeni maximální kapacitou zásobníku, pomocí něhož systém provádí rekurzivní volání. Iterativní verze mají při výpočtu konstantní paměťové nároky a podobné nebezpečí u nich tedy nehrozí. • Z těchto důvodů je i jazyk Lisp vybaven prostředky dovolujícími explicitní používání iteračních konstrukcí, ačkoli neodpovídají klasickému funkcionálnímu stylu.
Speciální funkce do • (do ((var1 ini-forma1 opak-forma1) • (var2 ini-forma2 opak-forma2) • ... • (varN ini-formaN opak-formaN)) • (test výraz1 výraz2 ... výrazK) • forma1 • forma2 • ... • formaM ) • kde každé opak-formaI nebo ini-formaI i opak-formaI může být prázdné a stejně tak test i výraz1 až výrazK mohou být prázdné.
Vyhodnocení formy do • 1. Vyhodnotí se všechny výrazy ini-formaI určující počáteční hodnoty proměnných cyklu. • 2. Výsledné hodnoty se naváží na proměnné; kde hodnota nebyla uvedena, dosadí se nil. • 3. Je-li testovací klauzule neprázdná, vyhodnotí se test a (a) je-li úspěšný, vyhodnotí se postupně všechny výrazy v klauzuli, cyklus se ukončí a výsledkem je hodnota posledního výrazu, (b) je-li neúspěšný, pokračuje se krokem (5). • 4. Je-li testovací klauzule prázdná, cyklus končí s hodnotou nil. • 5. Vyhodnotí se postupně všechnu formy těla cyklu. • 6. Vyhodnotí se všechny části opak-formI.
7. Hodnoty získané v kroku (6) se naváží na příslušné proměnné. • 8. Pokračuje se krokem (3). • Při použití do je podstatné si uvědomit, že vyhodnocení počátečních podmínek i změn hodnot proměnných se provádí dříve, než se jakákoliv z těchto hodnot naváže na příslušnou proměnnou – vlastně jakoby paralelně. Chování cyklu tedy vůbec nezávisí na pořadí, v jakém uvedeme na začátku cyklu jednotlivé proměnné.
Speciální funkce dolist a dotimes • (dolist (var list-forma result-forma) • forma1 ... formaN) • Při vyhodnocování se proměnné var postupně přiřazují jednotlivé prvky seznamu list-forma, přičemž pro každou hodnotu se provede vyhodnocení forem těla cyklu. Výsledná hodnota je pak určena hodnotou formy result-forma. • (dotimes (var pocet-forma result-forma) • forma1 ... formaN) • Při vyhodnocování se proměnné var postupně přiřazují hodnoty od 0 do hodnoty počet-forma – 1, přičemž pro každou hodnotu se provede vyhodnocení forem těla cyklu. Výsledná hodnota je pak určena hodnotou formy result-forma.
Speciální funkce prog • (prog1 výrazl výraz2 ... výrazN) • (prog2 výrazl výraz2 ... výrazN) • (progn výrazl výraz2 ... výrazN) • (progv (varl var2 ... varN) • (expl exp2 ... expN) • formal forma2 ... formaM) • Funkce prog1, prog2 a progn vyhodnotí postupně své argumenty; prog1 vrací hodnotu prvního výrazu, prog2 vrací hodnotu druhého a progn vrací hodnotu posledního. Všechny tyto funkce tedy vytvářejí obdobu složeného příkazu z jazyka Pascal. • Funkce progv nejprve vyhodnotí všechny výrazy expl až expN, pak naváže jejich hodnoty na odpovídající proměnné, a potom postupně vyhodnocuje formy v ní obsažené. Výsledkem je hodnota poslední formy.
Speciální funkce LET • (let ((var1 výraz1) • (var2 výraz2) • ... • (varN výrazN)) • formal forma2 ... formaM) • VarI je symbolický atom označující zaváděnou lokální proměnnou a výrazI je (počáteční) hodnota přiřazená této proměnné. Všechny výrazy počátečních hodnot se vyhodnotí dříve, než se provede jejich přiřazení proměnným. Na pořadí zápisu dvojic (proměnná výraz)tedy nezáleží. Je také možné inicializační výraz vůbec neuvést a příslušná proměnná má pak počáteční hodnotu nil. • Postupně se vyhodnotí forma1 až formaM, přičemž výsledkem je hodnota poslední formy.
Mapovací funkcionály • (mapcar fce-forma list-forma1 … list-formaN) • Funkcionál mapcar aplikuje funkci, která je hodnotou výrazu fce-forma na jednotlivé (stejnolehlé) prvky seznamů (tyto seznamy jsou hodnotami forem list-formaI ) a vrací seznam výsledků. • (mapc fce-forma list-forma1 … list-formaN) • Funkcionál mapc aplikuje funkci na jednotlivé (stejnolehlé) prvky seznamů a vrací triviální hodnotu (zpravidla nil nebo první seznam). • (maplist fce-forma list-forma1 … list-formaN) • Funkcionál maplist aplikuje funkci na celé seznamy, pak na jejich zbytky, atd. a vrací seznam výsledků. • (mapl fce-forma list-forma1 … list-formaN) • Funkcionál mapl aplikuje funkci na celé seznamy, pak na jejich zbytky, atd. a vrací triviální hodnotu (zpravidla nil nebo první seznam).
Lambda výraz • (lambda (var1 var2 ... ) • výraz1 výraz2 ... ) • Úkolem lambda-výrazu je vytvořit z výrazu funkci. K tomu je třeba určit, jaké jsou vázané proměnné funkce (neboli její parametry) a jaký je výraz definující funkční hodnotu. • Tyto dvě části uvedené symbolem lambda vytvářejí zápis lambda-výrazu. Výsledná hodnota je v duchu zvyklostí určena hodnotou posledního výrazu. • Lambda-výraz používáme buď pro zavedení anonymní funkce v místě jejího použití nebo jako prostředek lokálního přizpůsobení počtu argumentů nějaké funkce (a fixaci zbývajících).
Definice a vyhodnocení makra • (defmacro jméno-makra (par1 par2 ... parN) • výraz1 • výraz2 • ... • výrazN) • Při vyhodnocení aplikace makra se na parametry navážou nevyhodnocené argumenty a pro ně se provede vyhodnocení jednotlivých výrazů v rámci prostředí určeného definicí makra. Tato první etapa vyhodnocení se nazývá expanze makra a jejím výsledkem je hodnota posledního z výrazů těla definice makra. • Výsledek expanze se pak opět považuje za E-výraz, který se znovu vyhodnotí, tentokrát ale v prostředí místa aplikace makra.