1. Od Scheme k Lispu

Podobné dokumenty
Paradigmata programování 2

PARADIGMATA OBJEKTOVÉHO PROGRAMOVÁNÍ I

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

Paradigmata programování 1

FUNKCIONÁLNÍ A LOGICKÉ PROGRAMOVÁNÍ 3. CVIČENÍ

FUNKCIONÁLNÍ A LOGICKÉ PROGRAMOVÁNÍ 5. CVIČENÍ

Přednáška 3. Rekurze 1

Paradigmata programování 1

Objektově orientované programování

Objektové programování

Paradigmata programování 1

Paradigmata programování 1

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

Paradigmata programování II Korutiny a nedeterminismus

PARADIGMATA PROGRAMOVÁNÍ 2A INTERPRET S VEDLEJŠÍMI EFEKTY A MAKRY

Paradigmata programování 1 poznámky k přednášce. 3. Rekurze 1

Hanojská věž. T2: prohledávání stavového prostoru. zadání [1 1 1] řešení [3 3 3] dva možné první tahy: [1 1 2] [1 1 3]

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

Funkcionální programování úvod

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

LISP Definice funkcí

Programujeme v softwaru Statistica

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

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

Teorie informace a kódování (KMI/TIK) Reed-Mullerovy kódy

FUNKCIONÁLNÍ A LOGICKÉ PROGRAMOVÁNÍ 2. CVIČENÍ

Definice. Vektorový prostor V nad tělesem T je množina s operacemi + : V V V, tj. u, v V : u + v V : T V V, tj. ( u V )( a T ) : a u V které splňují

Paradigmata programování II Přednáška 2: Mutace

Assembler - 5.část. poslední změna této stránky: Zpět

PARADIGMATA PROGRAMOVÁNÍ 2 KORUTINY, NEDETERMINISMUS

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 21.

KAPITOLA 9 - POKROČILÁ PRÁCE S TABULKOVÝM PROCESOREM

Skripta ke školení. Základy VBA. vypracoval: Tomáš Herout. tel:

Paradigmata programování II Přednáška 1: Vedlejší efekt

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

Seminář IVT. MS Excel, opakování funkcí

DUM 06 téma: Tvorba makra pomocí VBA

12 DYNAMIKA SOUSTAVY HMOTNÝCH BODŮ

Funkce - opakování. Funkce může přijímat parametry na vstupu a může vracet parametry na výstupu.

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

PARADIGMATA PROGRAMOVÁNÍ 2A MAKRA I

Programovací jazyk Pascal

Cvičení Programování I. Stručné poznámky ke cvičení ze

DATABÁZE MS ACCESS 2010

Pokročilé programování v jazyce C pro chemiky (C3220) Třídy v C++

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ů

PARADIGMATA PROGRAMOVÁNÍ 2A MAKRA III

Matematická analýza pro informatiky I. Limita funkce

Stefan Ratschan. Fakulta informačních technologíı. Evropský sociální fond Praha & EU: Investujeme do vaší budoucnosti

Domény. Petr Štěpánek. S využitím materialu Krysztofa R. Apta

Negativní informace. Petr Štěpánek. S použitím materiálu M.Gelfonda a V. Lifschitze. Logické programování 15 1

Výroková logika - opakování

DSL manuál. Ing. Jan Hranáč. 27. října V této kapitole je stručný průvodce k tvorbě v systému DrdSim a (v

NPRG030 Programování I, 2015/16 1 / :25:32

Výjimky a ošetřování chyb v PHP. Who is General Failure and why is he reading my disk?!

Úvod do databázových systémů

8.3). S ohledem na jednoduchost a názornost je výhodné seznámit se s touto Základní pojmy a vztahy. Definice

Preprocesor. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík, 2016

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

2.1 Podmínka typu case Cykly Cyklus s podmínkou na začátku Cyklus s podmínkou na konci... 5

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

Parsování v Haskellu, knihovna Parsec

Programování v jazyce C a C++

Funkční objekty v C++.

Je n O(n 2 )? Je n 2 O(n)? Je 3n 5 +2n Θ(n 5 )? Je n 1000 O(2 n )? Je 2 n O(n 2000 )? Cvičení s kartami aneb jak rychle roste exponenciála.

Algoritmizace a programování

Objektově orientované programování v jazyce Python

Definice funkcí a procedur. Mnoho operací provozujeme opakovaně, proto je hloupé programovat je při každém použití znovu.

1 Linearní prostory nad komplexními čísly

Vzorce. StatSoft. Vzorce. Kde všude se dá zadat vzorec

NPRG030 Programování I, 2016/17 1 / :58:13

5 Orientované grafy, Toky v sítích

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.

Microsoft Office. Excel vyhledávací funkce

PARADIGMATA PROGRAMOVÁNÍ 2A VEDLEJŠÍ EFEKT

Programování II. Návrh programu I 2018/19

Grafy. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 13.

Úvod do logiky (VL): 5. Odvození výrokových spojek z jiných

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

Přednáška 3: Limita a spojitost

Matematická analýza pro informatiky I. Limita posloupnosti (I)

programátorský manuál

Úvod do informatiky. Miroslav Kolařík

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

Logické programování

Funkce, podmíněný příkaz if-else, příkaz cyklu for

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 12.

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

CZ.1.07/1.5.00/

ALGORITMIZACE PRAKTICKÉ

ZÁKLADY PROGRAMOVÁNÍ & ALGORITMIZACE VE VBA

Reprezentace aritmetického výrazu - binární strom reprezentující aritmetický výraz

PODOBÁ SE JAZYKU C S NĚKTERÝMI OMEZENÍMI GLOBÁLNÍ PROMĚNNÉ. NSWI162: Sémantika programů 2

Informatika 8. třída/6

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

Matematická logika. Miroslav Kolařík

Překladač a jeho struktura

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

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

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

Transkript:

KATEDRA INFORMATIKY UNIVERZITA PALACKÉHO V OLOMOUCI www.inf.upol.cz Michal Krupka krupka.inf.upol.cz michal.krupka@upol.cz 7. listopadu, 77 46 Olomouc Paradigmata programování poznámky k přednášce. Od Scheme k Lispu verze z 7. března 09 V předmětu Paradigmata programování přejdeme od Scheme k jazyku Common Lisp a vývojovému nástroji LispWorks. Na přednášce jsme probrali základní rozdíly mezi Schemem a Common Lispem. Ve zvláštním dokumentu máte k dispozici slovníček s překladem operátorů Scheme do Lispu. Kromě zvládnutí základů jazyka je třeba, abyste se dobře obeznámili s vývojovým prostředím LispWorks, kterému se tady nevěnuji. Uživatelské příručky lze nalézt buď na webu LispWorks, nebo přímo v aplikaci. Logické hodnoty V jazyce Scheme slouží k reprezentaci logických hodnot hodnoty #t (pravda) a #f (nepravda). V Common Lispu tuto úlohu hrají symboly t a nil. Na rozdíl od Scheme se tedy nejedná o hodnoty speciálního typu, ale o symboly. Jejich zvláštností je, že se vyhodnocují samy na sebe, podobně jako například čísla: CL-USER 7 > nil CL-USER 8 > t T Zařídit, aby hodnotou symbolu byl tento symbol samotný je ovšem snadné; ve Scheme by se dalo napsat například (define a 'a), v Common Lispu například (defvar a 'a). V Common Lispu se (stejně jako v některých variantách Scheme) používají tzv. zobecněné logické hodnoty: hodnotu pravda může reprezentovat libovolná hodnota kromě symbolu nil, hodnotu nepravda pak symbol nil. V literatuře o Common Lispu i v tomto textu je zvykem psát slovo pravda místo konkrétnější hodnoty v případě, že je tato hodnota podstatná pouze jako logická hodnota. V tomto kontextu se také používá slovo nepravda jako synonymum pro symbol nil. Jako argumenty logických operací je tedy možno používat jakékoliv hodnoty a samotné logické operace mohou jako hodnotu pravda místo symbolu t vracet jiný, v dané situaci užitečnější objekt. Příklad

Výraz (and a b c) vrací pravdu, pokud hodnoty a, b i c jsou pravda. Díky použití zobecněných logických hodnot je možno, aby proměnné a, b, c nabývaly i jiných hodnot než jenom t nebo nil, a hodnotou celého výrazu může být i něco jiného, než jen symboly t a nil. Makro and je například definováno tak, že pokud jsou všechny jeho argumenty pravda (rozumějme: různé od nil), vrací hodnotu posledního z nich. Výraz, který vrátí číslo 3, pokud je x rovno a y rovno, a jinak vrátí nil, se dá napsat takto: (if (and (= x ) (= x )) 3 nil) nebo takto: (when (and (= x ) (= x )) 3) (s makrem when se ještě setkáme), nebo jednoduše takto: (and (= x ) (= y ) 3) Pokud bychom navíc třeba chtěli, aby v případě negativního výsledku výraz nevracel nil, ale nulu, můžeme použít makro or, které také pracuje se zobecněnými logickými hodnotami, a napsat jej takto: (or (and (= x ) (= y ) 3) 0) Prázdný seznam V Common Lispu není žádná zvláštní hodnota reprezentující prázdný seznam. Roli prázdného seznamu hraje symbol nil: CL-USER 9 > '() CL-USER 0 > (cons nil) () Stejně jako v jazyce Scheme se funkcím, které vrací hodnotu pravda nebo nepravda, říká predikáty. V jazyce Scheme je obvyklé ukončovat názvy predikátů otazníkem, v Common Lispu koncovkou p nebo -p (i když se často setkáme s výjimkami).

3 Rozdíly ve vyhodnocovacím procesu V Common Lispu může symbol sloužit současně jako název funkce i jako název proměnné. Tyto dvě role symbolů spolu nekolidují. V terminologii Common Lispu se říká, že každý symbol má dvě vazby: hodnotovou a funkční. Pomocí každé z těchto vazeb může být symbol svázán s nějakou hodnotou. V případě vazby hodnotové s libovolnou hodnotou, v případě vazby funkční s funkcí. Je-li symbol svázán funkční vazbou s nějakou funkcí, říkáme, že je názvem této funkce. V případě hodnoty svázané se symbolem hodnotovou vazbou hovoříme prostě o hodnotě symbolu (či, volněji, hodnotě proměnné). Dvojí role symbolů tedy umožňuje používat stejné názvy pro proměnné a funkce. Proto například můžeme napsat: (defun encap-car (list) (list (car list))) (pomocí makra defun se v Common Lispu definují funkce; viz níže uvedený doslovný překlad do Scheme). Funkce encap-car vrací jednoprvkový seznam obsahující první prvek seznamu list: CL-USER > (encap-car '( 3)) () Ve Scheme by doslovná analogie definice této funkce vypadala takto: (define (encap-car list) (list (car list))) Scheme nesprávně a volání (encap-car '( )) by skončilo chybou (proč?). Existence dvojí vazby symbolů vede k několika komplikacím. Jde zejména o dva případy: když chceme zavolat funkci uloženou v proměnné a když chceme zjistit funkci podle jejího názvu. K ilustraci těchto problémů nejprve uveďme následující definici procedury na kompozici dvou procedur v jazyce Scheme: (define (comp a b) (lambda (x) (a (b x)))) Scheme Analogická definice v Common Lispu by vypadala takto: 3

(defun comp (a b) (lambda (x) (a (b x)))) nesprávně a vedla by k nepředvídatelným důsledkům, protože ve výrazu (a (b x)) by se nepoužily aktuální hodnoty proměnných a a b, ale došlo by k pokusu aplikovat funkce se jmény a a b, o kterých není jasné, jestli by existovaly a pokud ano, co by dělaly. V naší definici potřebujeme volat nikoli funkce, jejichž jména jsou a a b, ale funkce, které jsou hodnotami proměnných a a b, tedy jsou se symboly a, b svázány hodnotovou, nikoliv funkční vazbou. Pro podobné situace je v Common Lispu připravena funkce funcall, která volá funkci, již najde ve svém prvním argumentu. Správná definice funkce comp v Common Lispu je tedy následující: (defun comp (a b) (lambda (x) (funcall a (funcall b x)))) Ke druhému problému: pomocí funkce comp a funkcí car a cdr lze snadno vyjádřit funkci, která vrací druhý prvek daného seznamu (tedy funkci cadr). Ve Scheme by takovou funkci (proceduru) vracel výraz (comp car cdr) Scheme V Common Lispu by vyhodnocení tohoto výrazu opět vedlo k nepředvídatelným důsledkům, protože by se v něm nepoužily funkční, ale hodnotové vazby symbolů car a cdr. Abychom získali funkce car a cdr, musíme použít speciální operátor function. Funkce car a cdr získáme vyhodnocením výrazů (function car) a (function cdr). Analogický výraz v Common Lispu by tedy správně vypadal takto: (comp (function car) (function cdr)) Pro výraz (function name) se používá zkratka #'name, takže uvedený výraz je možno napsat stručněji: (comp #'car #'cdr) U většiny funkcí v Common Lispu, které požadují jako argument funkci, je místo funkce možné zadat její název (tj. symbol). To platí i pro funkci funcall; proto je kompozici funkcí car a cdr možno vytvořit i takto: 4

(comp 'car 'cdr) Dvojí vazby symbolů představují jediný významný rozdíl mezi vyhodnocovacím procesem Scheme a Common Lispu. Pro zopakování: Chceme-li zavolat funkci uloženou v proměnné a s argumenty p,..., pn, nestačí jako ve Scheme napsat (a p... pn) Scheme ale (funcall a p... pn) Chceme-li získat funkci s názvem f, musíme místo prostého f Scheme uvést #'f což je zkratka pro (function f) Kvůli zopakování uvádíme na obrázku zjednodušený popis vyhodnocovacího procesu v Common Lispu. Tento vyhodnocovací proces je stejně jako ve Scheme rekurzivní; kdekoli se v popisu na obrázku hovoří o vyhodnocení nějakého výrazu, znamená to spuštění celého vyhodnocovacího procesu od začátku na tento výraz. Zjednodušený vyhodnocovací proces v Lispu: Vyhodnocení výrazu E v prostředí env Je-li E symbol, výsledkem je hodnota symbolu E v prostředí env. Je-li E jiný atom než symbol, výsledkem je E. Je-li E seznam s operátorem o a argumenty a,..., a n, pak Jestliže o je speciální operátor, seznam se vyhodnotí podle pravidel tohoto speciálního operátoru. 5

Jinak o musí být název funkce.. Vyhodnocením (function o) (neboli #'o) v prostředí env se zjistí funkce f,. zjistí se hodnoty v,..., v n argumentů a,..., a n v prostředí env (opět vyhodnocovacím procesem). 3. Výsledkem vyhodnocení je výsledek aplikace funkce f na hodnoty v,..., v n. 4 Obyčejné λ-seznamy λ-seznam je seznam specifikující parametry funkce. U operátoru lambda je to první jeho argument, u makra defun druhý. λ-seznamům funkcí se říká obyčejné λ-seznamy, aby se odlišily od λ-seznamů s jiným účelem. Nejjednodušší λ-seznam je seznam povinných parametrů. S tím jsme se už setkali. Pokud chceme λ-seznamem stanovit, že funkce bude mít i nepovinné parametry, uděláme to pomocí klíčových slov. Základní z nich jsou &rest, &optional a &key. Klíčové slovo &rest uvádí parametr, který bude při aplikaci funkce obsahovat seznam všech zbylých argumentů. Umožňuje tedy definovat funkce akceptující neomezený (teoreticky) počet argumentů. Funkce + a * akceptují libovolný (i nulový) počet argumentů, mohly by tedy mít tento λ-seznam: (&rest numbers) Funkce - a / mají jeden parametr povinný, jejich λ-seznam by mohl být (number &rest numbers) Ukázka. Definujme funkci f takto: (defun f (a b &rest rest) (print a) (print b) (print rest) nil) Test: 6

CL-USER > (f ) CL-USER > (f 3) (3) CL-USER 3 > (f 3 4) (3 4) Klíčové slovo &optional uvádí nepovinné parametry dané pozičně. Defaultní hodnota parametrů je nil. To lze změnit, pokud místo parametru uvedeme dvouprvkový seznam, jehož prvním prvkem je parametr a druhým výraz, který se v momentě aplikace funkce vyhodnotí na defaultní hodnotu. Možná podoba λ-seznamu funkce log je tedy tato: (number &optional (base (exp ))) (funkce defaultně počítá logaritmus o základu e, lze ovšem nepovinně zadat jiný základ). Volání této funkce s méně než jedním a více než dvěma argumenty vede k chybě. Ukázka. Definujme funkci g takto: (defun g (a &optional b (c 0) (d (list a b c))) (print a) (print b) (print c) (print d) nil) Test: 7

CL-USER 7 > (g ) 0 ( 0) CL-USER 8 > (g ) 0 ( 0) CL-USER 9 > (g 3) 3 ( 3) CL-USER 0 > (g 3 4) 3 4 Klíčové slovo &key uvádí nepovinné parametry dané jménem. Jako jméno slouží symboly začínající dvojtečkou. Ty se vyhodnocují samy na sebe. Na přednášce jsme si ukazovali, jak s &key-parametry pracuje funkce find. Ukázka. Definujme funkci h takto: (defun h (a &key b (c 0) (d (list a b c))) (print a) (print b) (print c) (print d) nil) 8

Test: CL-USER > (h ) 0 ( 0) CL-USER 3 > (h :c 3) 3 ( 3) CL-USER 4 > (h :c 3 :d 4) 3 4 Zjištění použití nepovinných parametrů Někdy se u nepovinných parametrů hodí možnost poznat, zda uživatel příslušný argument vůbec použil, nebo ne. Pokud je například λ-seznam funkce fun (&optional x), pak nepoznáme, jestli uživatel funkci volal takto: (f), nebo takto: (f nil). K rozlišení těchto možností můžeme použít tříprvkový seznam, jehož první a druhý prvek jsou jako dříve parametr a defaultní hodnota a třetí prvek je další parametr, do nějž se při volání funkce uloží informace, zda byl nepovinný parametr použit, nebo ne. Příklad: (defun fun (&optional (x nil usedp)) (print (if usedp "Parametr použit" "Parametr nepoužit")) x) Test: CL-USER 9 > (fun ) "Parametr použit" 9

CL-USER 0 > (fun nil) "Parametr použit" CL-USER > (fun) "Parametr nepoužit" Tuto metodu lze použít i u &key-parametrů. Klíčová slova λ-seznamů lze i kombinovat. To zatím nebudeme potřebovat. Otázky a úkoly na cvičení Úlohy se týkají interpretu Scheme z konce minulého semestru přepsaného do Lispu. Interpret máte k dispozici jako zdrojový kód k této přednášce.. Vyřešte problém interpretu se zacyklením při pokusu o vyhodnocení symbolu bez vazby (viz jeden z testů na konci zdrojového souboru). Na hlášení chyby použijte funkci error: (error "Chybová hláška").. Doplňte do interpretu speciální operátory begin, let, let*. 3. Vylepšete funkci eval-pair tak, aby ji nebylo nutné předělávat, kdykoliv chceme do interpretu přidat nový speciální operátor. Můžete například vytvořit seznam speciálních operátorů a názvů funkcí, které se spouštějí při jejich vyhodnocování a uložit jej do globální proměnné: (defvar *special-operators*) (setf *special-operators* '((quote. eval-quote) (if. eval-if) (define. eval-define) (lambda. eval-lambda))) 0