JUI - 1. přednáška Funkcionální programování Úvod do jazyka Lisp RNDr. Jiří Dvořák, CSc.
2 Principy funkcionálního programování Funkcionální program se vytváří jako souhrn definic funkcí a jejich aplikací ve formě výrazů. Jedná se o to, jak vyjádřit daný algoritmus pomocí vzájemně provázaných (zpravidla rekurzivních) funkcí. Výpočet podle takového programu lze chápat jako provedení aplikace nějaké funkce na určitou sadu hodnot jejích argumentů, jehož smyslem je získat výslednou hodnotu. Počítač má ve funkcionálním programování roli vyhodnocovače výrazů. Základním krokem vyhodnocení je přitom zjednodušení (redukce) výrazu. Výsledek výpočtu je do značné míry nezávislý na pořadí, v němž se redukují jednotlivé dílčí výrazy. To umožňuje snížení rizika možných chyb programování, a vyúsťuje např. do úvah o paralelním provádění redukčních transformací na počítačích, jejichž technická realizace už nemusí vycházet z von Neumannova modelu.
3 Počítač jako vyhodnocovač výrazů Prostředí Vyhodnocení DefiniceVýrazy Výsledky
4 Rekurze V neimperativním programovacím stylu je rekurze důležitým nástrojem pro řešení složitých problémů. Taxonomie rekurzivních definic (pro funkcionální styl): Vnořená rekurze - rekurzivní volání funkce obsahuje v argumentech volání téže funkce. Kaskádní (stromová) rekurze - ve stejném výrazu se objevuje několik rekurzivních volání, ale bez vzájemného vnoření. Lineární rekurze - v každé z alternativ v definici funkce se vyskytuje nejvýše jedno její rekurzivní volání. Koncová rekurze - speciální případ lineární rekurze, kdy rekurzivní volání je poslední operací příslušné alternativy definice.
5 Historie jazyka Lisp Jazyk Lisp je jedním z nejstarších dosud používaných programovacích jazyků. Původně vznikl koncem 50. let (Mc Carthy, 1960) jako určitá notace pro zápis algoritmů pracujících se seznamy (LISP = LISt Processing). Další verze jazyka Lisp: Lisp 1.5 (Mc. Carthy, 1962), MacLisp (1974), InterLisp (1978), Franz Lisp, Zeta Lisp, Scheme, Common Lisp (1984), Xlisp (1986)
6 Typy dat Souhrnně se data v Lispu nazývají S-výrazy (symbolické výrazy). Jednoduché typy dat - atomy: číselné: celočíselné, reálné symbolické: speciální znaky, identifikátory (mohou obsahovat písmena, číslice, pomlčku a podtržítko; obvykle se nerozlišují velká a malá písmena). Strukturované typy dat: tečka-dvojice seznam (speciální případ tečky-dvojice ve zkrácené notaci)
7 Tečka-dvojice Tečka-dvojice: (S-výraz1.S-výraz2) Tečka-dvojice představuje binární strom, kde S-výraz1 odpovídá levému podstromu a S-výraz2 pravému podstromu. Tečka-dvojice je fyzicky reprezentována základní lispovskou buňkou (tzv. cons-buňkou), dělenou na 2 části, které obsahují ukazatele na příslušné podvýrazy. Názvy těchto částí jsou dány historicky (označují části strojového slova na počítači IBM 1040 kde byl Lisp poprvé implementován). address partdecrement part S-výraz1S-výraz2
8 Seznam Seznam: (S-výraz1 S-výraz2 … S-výrazN) Seznam je tvořen posloupností S-výrazů oddělených mezerami a uzavřených do kulatých závorek. Zápis seznamu v podobě tečky-dvojice: (S-výraz1.(S-výraz2.( ….(S-výrazN.nil)… ))) Atom nil je speciální atom, který reprezentuje konec seznamu. Fyzická implementace seznamu: … S-výraz1S-výraz2S-výrazN
9 Struktura programu Program v Lispu se skládá z tzv. forem. Forma (E-výraz) je S-výraz, který lze vyhodnotit lispovským interpretem. Program je tedy posloupností vyhodnotitelných S-výrazů, což znamená, že program má stejný charakter jako jím zpracovávaná data. Typy forem: číselný atom symbolický atom (identifikátor) zápis funkce
10 Atomické formy Číselný atom: Vyhodnocením se získá číslo vyjádřené zápisem atomu. Symbolický atom (identifikátor): Je považován za proměnnou a jeho vyhodnocením se získá hodnota, která je v daném okamžiku vázána na daný atom. Pokud v okamžiku vyhodnocení není na daný atom žádná hodnota navázána, je signalizována chyba. Proměnné se standardně přiřazenou hodnotou: T… hodnota je T (true) NIL… hodnota je NIL F… hodnota je NIL Pozn.: platí konvence, že jakákoli hodnota různá od NIL vyjadřuje pravdivostní hodnotu true.
11 Zápis funkce Zápis funkce (přesněji zápis aplikace funkce) má tvar seznamu vytvořeného podle následujícího schématu: (f a 1 a 2 … a n ) kde f je jméno (atom) vyjadřující funkci a a 1, a 2, …, a n jsou formy vyjadřující argumenty, na něž se má funkce f aplikovat. Pro zápis funkce se v Lispu používá důsledně prefixová notace, přičemž se celý zápis uzavírá vždy do závorek. Při vyhodnocení zápisu funkce Lisp nejprve vyhodnotí všechny argumenty a teprve na získané hodnoty aplikuje funkci f. Pořadí vyhodnocování argumentů není v Lispu přesně specifikováno. Výjimkou z tohoto pravidla jsou speciální funkce, z nichž každá má specifická pravidla pro vyhodnocení (resp. nevyhodnocení) argumentů. Zápisy těchto funkcí se nazývají speciální formy.