Teorie programovacích jazyků
|
|
- Hana Matějková
- před 6 lety
- Počet zobrazení:
Transkript
1 Vysoké učení technické v Brně Fakulta informačních technologií Teorie programovacích jazyků Interprety a předávání parametrů Luboš Lorenc
2 Obsah 1 Interprety Jednoduchý interpret Podmíněné vyhodnocování Lokální vazby Procedury Přiřazení proměnných Rekurze Dynamický rozsah platnosti proměnných a dynamické přiřazení Dynamický rozsah platnosti proměnných Dynamické přiřazení Vlastnosti a porovnání obou metod Předávání parametrů Podpora polí Předávání parametrů odkazem Předávání hodnotou-odkazem a předávání výsledkem Vyjadřované nebo označované hodnoty? Předávání jménem a předávání s vyhodnocením při potřebnosti Závěr Použitá literatura... 28
3 1 Interprety V této kapitole postupně vytvoříme jednoduchý interpret používající základní sémantiku mnoha moderních programovacích jazyků. Začneme nejjednodušší možnou verzí, která dokáže interpretovat pouze literály, proměnné a aplikace. Potom budeme postupně v jednotlivých krocích přidávat další formy. 1.1 Jednoduchý interpret Jednou z důležitých částí specifikace jakéhokoliv programovacího jazyka je množina hodnot, se kterými má daný jazyk manipulovat. Nás budou nyní zajímat dvě podmnožiny této množiny. A to množina vyjadřovaných hodnot a množina označovaných hodnot. Vyjadřované hodnoty označují možné výsledky výrazů a označované hodnoty jsou hodnoty vázané k proměnným. Vyjadřované hodnoty tedy obvykle představují například čísla, řetězce, znaky a podobně. Označované hodnoty pak obvykle chápeme jako proměnné, respektive jako paměťové buňky obsahující nějaké hodnoty. Pro jednoduchost bude náš jazyk obsahovat pouze dva typy vyjadřovaných hodnot - celá čísla a procedury. V této chvíli nebudeme rozlišovat mezi označovanými a vyjadřovanými hodnotami. Můžeme tedy uvést vztahy: Vyjadřovaná hodnota = Číslo + Procedura Označovaná hodnota = Číslo + Procedura Nyní potřebujeme ještě rozlišit dva druhy jazyků: Definovaný jazyk je jazyk, který specifikujeme vytvářeným interpretem a definující jazyk je jazyk, v němž píšeme (vytváříme) interpret. Než přistoupíme ke konstrukci interpretu, uvedeme si ještě konkrétní a abstraktní syntaxi definovaného jazyka: <exp> ::= <integer-literal> lit (datum) <varref> <operator> <operands> app (rator rands) <operator> ::= <varref> (<exp>) <operands> ::= () (<operand>) {,<operand>} * ) <operand> ::= <exp> <varref> ::= <var> varref (var) Abstraktní syntaktické stromy jsou poté vytvářeny ze záznamů, které obsahují definice typů a jsou založeny na abstraktních syntaktických jménech daných gramatikou (konkrétní syntaxí). (define-record lit (datum)) (define-record varref (var)) (define-record app (rator rands)) V této chvíli již můžeme přistoupit ke konstrukci interpretu
4 Příklad Jednoduchý interpret s větvením pro několik případů (define eval-exp (lambda (exp) (variant-case exp (lit (datum) datum) (varref (var) (apply-env init-env var)) (app (rator rands) (let ((proc (eval-exp rator)) (args (eval-rands rands))) (apply-proc proc args))) (else (error "Invalid abstract syntax: " exp))))) (define eval-rands (lambda (rands) (map eval-exp rands))) Symboly lit, varref, app, rator a rand(s) jsou zkratkami slov literál, odkaz na proměnnou (variable reference), aplikace, operátor a operand(y). Pole rands záznamu app obsahuje seznam abstraktních syntaktických stromů pro operandy aplikace. Hlavní procedura eval-exp zpracuje abstraktní syntaktický strom výrazu, který dostane jeho parametr a vrátí jeho vypočtenou hodnotu. Podívejme se blíže na činnost procedury eval-exp. Pokud exp je literál, je navrácen tento literál. Pokud je exp uzel, který reprezentuje proměnnou, hodnota výrazu bude hodnota vázaná k této proměnné. Nyní ale potřebujeme rozhodnout, odkud chceme získat tuto hodnotu. K tomu potřebujeme poskytnout nějaké prostředí. Tedy, potřebujeme nějakou konečnou funkci, která vezme daný symbol a vrátí příslušnou hodnotu, kterou tento symbol popisuje v daném prostředí. V našem jazyce máme (pro tuto chvíli) pouze jediné prostředí, a to počáteční prostředí init-env. Nyní nadefinujeme abstraktní datový typ (ADT) pro prostředí: Příklad definice ADT prostředí (define the-empty-env (create-empty-ff)) (define extend-env (extend-ff*)) (define apply-env apply-ff) Pokud vyčíslujeme nějakou proměnnou, interpret potřebuje pouze najít její vazbu v init-env. Proto je tedy v našem interpretu uvedena následující větev: (varref (var) (apply-env init-env var)) Tato větev umožňuje zpracování případu aplikace. Protože operátor může být jakýkoliv výraz, musíme ho nejprve vyčíslit, abychom získali proceduru, která má být zavolána. Toho je v našem interpretu jednoduše dosaženo pomocí rekurzivního volání (eval-exp-rator). Tak jak bývá obvyklé u většiny programovacích jazyků, i jazyk, který zpracovává náš interpret používá vyhodnocování v aplikačním pořadí - operandy každé operace jsou vyhodnoceny před voláním této procedury. Pro vyčíslení seznamu operandů a vytvoření seznamu argumentů (hodnot operandů) je volána pomocná procedura eval-rands používající map k rekurzivnímu vyvolávání eval-exp pro každý operand
5 Jakým způsobem bude aplikace provedena závisí na reprezentaci procedur. Tato závislost byla izolována do procedury apply-proc, čímž bylo umožněno kompletní vytvoření procedury eval-exp bez ohledu na způsob reprezentace procedur. Nyní se podíváme na reprezentaci procedur. Na začátku máme pouze jediný druh procedur: Primitivní procedury, které jsou podporovány přímo základní implementací. Abychom byli přesní, použijeme gramatiku v BNF pro specifikaci dat, se kterými má pracovat apply-proc: <Procedure> ::= <prim-op> prim-proc (prim-op) <prim-op> ::= <addition> + <subtraction> - <multiplication> * <increment> add1 <decrement> sub1 Tato specifikace určuje, že existují pouze primitivní procedury, jež mohou provádět právě jednu z pěti uvedených operací. Každá takováto procedura může být reprezentována pomocí záznamu (define-record prim-proc (prim-op)), což nám později umožní snadnější odlišení od jiných typů procedur. Jediná položka uložená v záznamu prim-proc je symbol označující použitý operátor. Procedury make-prim-proc a apply-proc definují abstraktní datový typ pro procedury. Jediné, co v této chvíli vykonává procedura apply-proc je ověření, zda její první parametr je primitivní procedura, a následné vyvolání apply-prim-op. Příklad Část interpretu - procedury apply-proc a apply-prim-op (define apply-proc (lambda (proc args) (variant-case proc (prim-proc (prim-op) (apply-prim-op prim-op args)) (else (error "Invalid procedure: " proc))))) (define apply-prim-op (lambda (prim-op args) (case prim-op ((+) (+ (car args) (cadr args))) ((-) (- (car args) (cadr args))) ((/) (/ (car args) (cadr args))) ((add1) (+ (car args) 1)) ((sub1) (- (car args) 1)) (else (error "Invalid prim-op name: " prim-op))))) Nyní nám ještě zbývá vytvořit počáteční prostředí definující symboly primitivních operátorů a máme vytvořený kompletní jednoduchý interpret. Příklad Počáteční prostředí (define prim-op-names '(+ - * add1 sub1)) (define init-env (extend-env prim-op-names (map make-prim-proc prim-op-names) the-empty-env)) - 3 -
6 1.2 Podmíněné vyhodnocování V této a následujích kapitolách budeme do definovaného jazyka postupně přidávat nové vlastnosti. Pro každou vlastnost přidáme do gramatiky pravidlo pro nonterminál <exp>, specifikujeme abstraktní syntaxi pro toto pravidlo a nakonec vložíme příslušnou větev do eval-exp pro zpracování nového typu uzlu abstraktního syntaktického stromu. Nejdříve přidáme podmíněné vyhodnocování výrazů s následující konkrétní a abstraktní syntaxí: <exp> ::= if <exp> then <exp> else <exp> if (test-exp then-exp else-exp) Abyhom nemuseli pro boolovské výrazy definovat nový datový typ, budeme nulu považovat za nepravdivou hodnotu a všechny ostatní hodnoty za pravdivé. K tomu účelu využijeme proceduru true-value?, která zavádí potřebnou abstrakci. Příklad Procedura true-value? (define true-value? (lambda (x) (not (zero? x)))) Požadovaného chování interpretu dosáhneme pouhým přidáním následující větve pro zpracování podmíněných příkazů do našeho interpretu. Příklad Větev vyhodnocující podmíněné příkazy (if (test-exp then-exp else-exp) (if (true-value? (eval-exp test-exp)) (eval-exp then-exp) (eval-exp else-exp))) Z uvedeného kódu je jasně patrné, jak silně závisí definovaný jazyk na chování jazyka definujícího. Pokud bychom nepochopili chování definujícího jazyka, nejsme z tohoto kódu schopni pochopit ani definovaný jazyk. 1.3 Lokální vazby V této chvíli dokáže náš interpret vyhodnocovat všechny výrazy pouze vzhledem k jedinému prostředí init-env. To je velmi významné omezení, které například nedovoluje definici lokálních proměnných uvnitř procedur a funkcí, jak bývá běžné ve většině programovacích jazyků. Abychom dosáhli nápravy, je nutné náš interpret poněkud upravit. Nejprve do našeho jazyka přidáme klíčová slova let a in sloužící k deklarování proměnných a jejich vázání v těle výrazu. Konkrétní syntaxe let formy je následující: <exp> ::= let <decls> in <exp> let (decls body) <decls> ::= <decl> {<decl>} * <decl> ::= <var> = <exp> decl (var exp) - 4 -
7 Ze zápisu konkrétní syntaxe je jasně patrné, že jednotlivé deklarace je možné zanořovat do sebe, což umožňuje unvnitř jednoho výrazu (procedury) deklarovat nové lokální proměnné pro jistý podvýraz. Odpovídající abstraktní syntaxe pak využívá následující typy záznamů: (define-record let (decls body)) (define-record decl (var exp)) Pole decls záznamu let je asociováno s nonterminálem, který se může opakovat nula nebo vícekrát - tedy obsahuje seznam záznamů decl. Tělo let výrazu by mělo být vyhodnoceno v prostředí, ve kterém jsou deklarované proměnné vázány k výsledkům výrazů na pravé straně deklarací, zatímco ostatní vazby by měly být získány z prostředí, ve kterém je vyhodnocován celý výraz. Proto musíme upravit proceduru eval-exp tak, aby zpracovávala dva argumenty - výraz a prostředí. Nová procedura eval-exp musí zadaný výraz vyhodnocovat v zadaném prostředí. Příklad Interpret s let (define eval-exp (lambda (exp env) (variant-case exp (lit (datum) datum) (varref (var) (apply-env env var)) (app (rator rands) (let ((proc (eval-exp rator env)) (args (eval-rands rands env))) (apply-proc proc args))) (if (test-exp then-exp else-exp) (if (true-value? (eval-exp test-exp env)) (eval-exp then-exp env) (eval-exp else-exp env))) (let (decls body) (let ((vars (map decl->var decls)) (exps (map decl->exp decls))) (let ((new-env (extend-env vars (eval-rands exps env) env))) (eval-exp body new-env)))) (else (error "Invalid abstract syntax: " exp))))) Pokud je vyhodnocován let výraz, jsou nejprve vyhodnoceny podvýrazy na pravé straně jeho deklarací. Jelikož rozsah platnosti těchto deklarací je omezen pouze na tělo výrazu, podvýrazy na pravé straně deklarací jsou pomocí eval-rands vyhodnoceny v původním prostředí celého výrazu. Tělo výrazu je poté vyhodnoceno v novém prostředí získaném rozšířením původního prostředí o nově deklarované proměnné pomocí extend-env. 1.4 Procedury Náš jazyk obsahuje stále pouze procedury obsažené v počátečním prostředí. Nyní proto doplníme možnost definovat vlastní procedury. Použijeme tuto konkrétní syntaxi: <exp> ::= proc <varlist> <exp> <varlist> ::= () (<vars>) <vars> ::= <var> {,<var>} * Při vyhodnocování aplikace procedury je její tělo vyhodnoceno v prostředí, ve kterém jsou její formální parametry vázány k argumentům této aplikace. Vázání proměnných vyskytujících se v - 5 -
8 těle procedury jako volné zůstávají zachována vůči původnímu prostředí. Procedury mohou být předávány jako parametry do jiných procedur, vráceny jako výsledky procedur a ukládány do datových struktur. Aby mohla procedura zachovávat vázání svých volných proměnných tak, jak byly vázány v čase jejího vytvoření, musí tvořit uzavřený celek nezávislý na prostředí, v němž byla vytvořena. Takovýto celek nazýváme uzávěr a obsahuje tělo procedury, její formální parametry a vázání jejích volných proměnných. Často též říkáme, že procedura je uzavřena vůči prostředí, v němž byla vytvořena. Uzávěry budeme reprezentovat jako záznamy: (define-record closure (formals body env)) Nyní musíme modifikovat proceduru apply-proc tak, aby kromě primitivních procedur neobsahujících uzávěry zohledňovala i uzávěry procedur nově definovaných. Proceduru můžeme popsat pomocí následující rovnice: Procedura = primitivní procedura + uzávěr Apply-proc tedy musí nejprve zkontrolovat, jaký typ procedury zpracovává. Pokud tato má uzávěr, jednoduše vyvolá tělo uzávěru v příslušně rozšířeném prostředí. Příklad Interpret podporující uživatelem definované procedury (define eval-exp (lambda (exp env) (variant-case exp (lit (datum) datum) (varref (var) (apply-env env var)) (app (rator rands) (let ((proc (eval-exp rator env)) (args (eval-rands rands env))) (apply-proc proc args))) (if (test-exp then-exp else-exp) (if (true-value? (eval-exp test-exp env)) (eval-exp then-exp env) (eval-exp else-exp env))) (let (decls body) (let ((vars (map decl->var decls)) (exps (map decl->exp decls))) (let ((new-env (extend-env vars (eval-rands exps env) env))) (eval-exp body new-env)))) (proc (formals body) (make-closure formals body env)) (else (error "Invalid abstract syntax: " exp))))) (define apply-proc (lambda (proc args) (variant-case proc (prim-proc (prim-op) (apply-prim-op prim-op args)) (closure (formals body env) (eval-exp body (extend-env formals args env))) (else (error "Invalid procedure: " proc))))) - 6 -
9 1.5 Přiřazení proměnných Dále potřebujeme do našeho interpretu přidat podporu pro přiřazování do proměnných pomocí operátoru přiřazení (:=). Nejdříve musíme změnit abstrakci našeho prostředí, neboť v současné době neposkytuje prostředky pro změnu hodnoty vázané k proměnné - každá proměnná je přímo vázaná ke své vyjadřované hodnotě. Označované hodnoty (hodnoty vazeb proměnných) a vyjadřované hodnoty (hodnoty výrazů) jsou tedy identické. Přímé vazby proměnných k jejich hodnotám nahradíme vazbami přes paměťové buňky. Proměnné již nebudou vázány přímo na své hodnoty, ale na příslušné paměťové buňky, jejichž obsah může být snadno modifikován pomocí přiřazení. Můžeme tedy uvést: Popisovaná hodnota = buňka (vyjadřovaná hodnota). Nyní provedeme modifikaci interpretu, aby jako označované hodnoty používal paměťové buňky. Tato operace vyžaduje dvě změny. První se týká procedury apply-proc v okamžiku vyvolání uzávěru - nové vazby musí být buňky obsahující argumenty. Namísto (extend-env formals args env) použijeme konstrukci (extend-env formals (map make-cell args) env). Druhá změna se týká procedury eval-exp. Pokud je ve výrazu použita proměnná, je nutné provést extrakci skutečné hodnoty z paměťové buňky, na kterou je tato proměnná vázána. Namísto (varref (var) (apply-env env var)) použijeme (varref (var) (cell-ref (apply-env env var))). Tento přístup, kdy jsou hodnoty operandů procedury uloženy v paměti je též znám pod názvem předávání hodnotou (call-by-value). Abychom do našeho interpretu mohli definitivně přidat operátor přiřazení, musíme ještě zavést jeho konkrétní snyntaxi <exp> ::= <var> := <exp> a abstraktní syntaxi založenou na záznamu: (define-record varassign (var exp)). Pro implementaci přiřazení musíme přidat následující větev do eval-exp: (varassign (var exp) (cell-set! (apply-env env var) (eval-exp exp env))) varassign (var exp) Prvky, které jsou předávány do cell-set! jsou obecně označovány jako L-hodnoty (mohou stát na levé straně operátoru přiřazení)
10 Příklad Interpret podporující přiřazování do proměnných (call-by-value) (define eval-exp (lambda (exp env) (variant-case exp (lit (datum) datum) (varref (var) (cell-ref (apply-env env var))) (app (rator rands) (let ((proc (eval-exp rator env)) (args (eval-rands rands env))) (apply-proc proc args))) (if (test-exp then-exp else-exp) (if (true-value? (eval-exp test-exp env)) (eval-exp then-exp env) (eval-exp else-exp env))) (proc (formals body) (make-closure formals body env)) (var-assign (var exp) (cell-set! (apply-env env var) (eval-exp exp env))) (else (error "Invalid abstract syntax: " exp))))) (define apply-proc (lambda (proc args) (variant-case proc (prim-proc (prim-op) (apply-prim-op prim-op args)) (closure (formals body env) (eval-exp body (extend-env formals (map make-cell args) env))) (else (error "Invalid procedure: " proc))))) 1.6 Rekurze Poslední vlastností, kterou je ještě nutné implementovat do našeho jednoduchého interpretu, je rekurze. Jednou možností, kterou lze využít, je operátor pevného bodu. Tato možnost je však spíše pouze teoretická, neboť je většinou velmi neefektivní pro rutinní praktické použití. Druhou možností je využití výrazu letrec. Výraz letrec je syntakticky transformován na výraz, který použije let k vytvoření prostředí s nadbytečnými vazbami proměnných. Rekurzivní procedury jsou vzhledem k tomuto prostředí uzavřeny. Díky tomu je následně možné využít nadbytečné vazby jejich asociovaných proměnných k uložení jejich uzávěrů v paměťových buňkách. Příklad Transformace příkazu letrec (letrec ((var 1 exp 1 )... (var n exp n )) body) (let ((var 1 *)... (var n *)) (let ((v 1 exp 1 )... (v n exp n )) (set! var 1 v 1 )... (set! var n v n ) unspecified) body - 8 -
11 v 1,...,v n jsou nové proměnné, které se nevyskytují nikde mimo výraz letrec. Unspecified je vloženo pouze proto, aby bylo zajištěno, že vnitřní let bude mít vždy nějaké tělo, i když nebude obsahovat žádné definice. Rekurzivní procedury jsou vytvářeny jejich uzavřením v prostředí obsahujícím proměnné, ke kterým budou vázány. Pokud bychom se pokusili o dereferenci kterékoliv proměnné var i v příkazu exp j před provedením příslušného příkazu set!, získáme nespecifikované hodnoty. Pokud ale každý výraz exp i bude lambda, potom je zaručeno, že k takovéto situaci nikdy nedojde a pořadí vyhodnocování nebude podstané. Kromě některých speciálních případů (jako jsou například streamy) bývá tato podmínka prakticky vždy splněna. Pro implementaci rekurze do našeho interpretu použijeme jistou variaci syntaxe příkazu letrec, která omezuje pravou stranu rekurzivních deklarací na výraz proc. Konkrétní a abstraktní syntaxe je popsána následující gramatikou: <exp> ::= letrecproc <procdecls> letrecproc (prodecls in <exp> body) <procdecls> ::= <procdecl> {;<procdecl>} * <procdecl> ::= <var> <varlist> = <exp> procdecl (var formals body) Levou stranu rekurzivní deklarace tvoří jméno rekurzivní procedury a seznam jejích formálních parametrů. Pravá strana je tvořena tělem této procedury. Abychom mohli začlenit letrecproc do našeho interpretu, musíme nejprve zavést do ADT prostředí nový operátor extend-rec-env, který rozšíří prostředí o množinu vzájemně rekurzivních procedur. Příklad Abstraktní datový typ pro prostředí bez cyklických uzávěrů podporující rekurzi (define-record extend-rec-env (vars vals old-env)) (define extend-rec-env (lambda (procdecls env) (make-extended-rec-env (map procdecl->var procdecls) (list->vector (map (lambda (procdecl) (make-proc (procdecl->formals procdecl) (procdecl->body procdecl))) procdecls)) env))) (define apply-env (lambda (env var) (variantcase env (extended-rec-env (vars vals old-env) (let ((p (ribassoc var vars vals *fail*))) (if (eq? p *fail*) (apply-env old-env var) (make-closure (map make-cell ((proc->formals p) (proc->body p))) env))))...))) - 9 -
12 Nyní již můžeme letrecproc začlenit do našeho interpretu. Přidáme jej jako novou větev do eval-exp. Tato větev bude velice podobná větvi pro eval-exp, pouze s tím rozdílem, že namísto extend-env bude použito extend-rec-env, čímž bude zajištěno vytvoření nového prostředí, ve kerém bude vyhodnoceno tělo procedury. Příklad Část interpretu - větev eval-exp pro vyhodnocení letrecproc (letrecproc (procdecls body) (eval-exp body (extend-rec-env procdecls env))) 1.7 Dynamický rozsah platnosti proměnných a dynamické přiřazení V této kapitole si ukážeme dvě možnosti pro zajištění dynamického přeuspořádávání informací v prostředí. První přístup, dynamický rozsah platnosti, je druh vázacího mechanizmu, který zvyšuje vyjadřovací sílu za cenu obtížnější pochopitelnosti programu. Druhý přístup, dynamické přiřazení, poskytuje skoro stejnou vyjadřovací schopnost jako dynamický rozsah platnosti a navíc nezpůsobuje ztrátu přehlednosti programu Dynamický rozsah platnosti proměnných Zatím jsme stále předpokládali, že tělo procedury je vždy vyhodnoceno v prostředí, v jakém byla tato procedura vytvořena. To je nutné, pokud mají být proměnné lexikálně vázané, ovšem, jak jsme mohli vidět, je na druhou stranu nutné vytvořit vždy nový uzávěr při každém volání procedury. Podstatně jednodušší by bylo, vyhodnocovat tělo každé procedury vždy v prostředí, ze kterého je tato procedura právě volána - použít dynamický rozsah platnosti proměnných nebo též dynamické vázání. Situaci, jež v tom případě nastane, ilustruje následující příklad. Příklad Rozdíl mezi technikami dynamický rozsah platnosti a lexikální vázání proměnných let a = 3 in let p = proc (x) +(x, a); a = 5 in *(a, p(2)) Pokud použijeme lexikální vázání proměnných, bude se tělo procedury p vyhodnocovat v prostředí, v jakém bylo vytvořeno, tedy proměnná a bude mít v průběhu vyhodnocování hodnotu 3 a výsledek celého výrazu bude 25. Pokud ale použijeme dynamický rozsah platnosti, bude se tělo procedury p vyhodnocovat v prostředí, v jakém bylo vyvoláno, tedy proměnná a bude mít v průběhu vyhodnocování hodnotu 5 a výsledek celého výrazu bude 35. Dynamické vázání se řídí následujícím pravidlem: Dynamická vazba je platná po dobu vyhodnocování těla asociovaného s vázací formou. Reference na dynamicky vázanou proměnnou odkazují vždy na nejposlednější platné vázání této proměnné
13 Ačkoliv je dynamické vázání proměnných obtížnější než lexikální vázání co se týče pochopitelnosti zdrojového programu, je podstatně jednodušší při implementaci překladače. Jelikož procedury již nejsou uzavřeny vzhledem k prostředí, nemusíme vytvářet jejich uzávěry obsahující prostředí, v němž byly vytvořeny, ale budeme používat pouze seznam formálních parametrů. Při vyhodnocování procedury tedy musí apply-proc pouze doplnit aktuální prostředí tak, aby získala nové prostředí, v němž se bude vyhodnocovat tělo procedury a toto prostředí předat do eval-exp. Pokud je do prostředí přidána nějaká vazba, pak zůstává platná tak dlouho, dokud nejsou odstraněny všechny následně přidané vazby. Jinak řečeno, prostředí se chová jako struktura typu LIFO (last-in-first-out). Tohoto chování můžeme výhodně využít a implementovat ADT prostředí tak, aby používal globální zásobník prostředí, čímž odpadne nutnost složitého předávání prostředí jako pomocného parametru procedur. Předání nového prostředí z apply-proc do Eval-exp (jak bylo naznačeno v předchozím odstavci), tedy bude provedeno jednoduše jeho uložením na globální zásobník prostředí v apply-proc. Po vyhodnocení těla procedury je samozřejmě nutné toto nové prostředí ze zásobníku odstranit, o což se též stará apply-proc. Příklad Interpret podporující dynamický rozsah proměnných (define eval-exp (lambda (exp) (variant-case exp (lit (datum) datum) (varref (var) (cell-ref (lookup-in-env var))) (app (rator rands) (let ((proc (eval-exp rator)) (args (eval-rands rands))) (apply-proc proc args))) (if (test-exp then-exp else-exp) (if (true-value? (eval-exp test-exp)) (eval-exp then-exp) (eval-exp else-exp))) (proc (formals body) exp) (var-assign (var exp) (cell-set! (lookup-in-env var) (eval-exp exp))) (else (error "Invalid abstract syntax: " exp))))) (define eval-rands (lambda (rands) (map (lambda (exp) (eval-exp exp)) rands))) (define apply-proc (lambda (proc args) (variant-case proc (prim-proc (prim-op) (apply-prim-op prim-op args)) (proc (formals body) (push-env! formals (map make-cell args)) (let ((value (eval-exp body))) (pop-env!) value)) (else (error "Invalid procedure: " proc)))))
14 Implementace s globálním zásobníkem prostředí může být nevýhodná v případě, že si vyhodnocení programu vyžádá mnoho proměnných a jejich hluboké zanoření v zásobníku prostředí. Jelikož tento musí být při vyhledávání nejposlednější platné verze dané proměnné procházen sekvenčně, může být celé vyhodnocování programu značně neefektivní. Interpret však lze modifikovat i tak, že se pro každou proměnnou použije separátní zásobník a v tom případě vyhledávání zcela odpadne, neboť nejposlednější platná verze je vždy na vrcholu příslušného zásobníku. Ovšem, v tomto případě může být poněkud časově složitější vyvolávání procedur, neboť tato akce pak obecně představuje ukládání údajů do několika zásobníků a po vyhodnocení procedury jejich opětné vyjímání. Poměrně podstatnou nevýhodou dynamického rozsahu platnosti proměnných však je to, že při jeho použití nelze na program aplikovat různé transformační techniky jako jsou například α-, β-, η-konverze, které je možné aplikovat při použití lexikálního vázání proměnných Dynamické přiřazení Interprety, které jsme vytvořili před zavedením dynamického rozsahu platnosti proměnných, používaly lexikální vázání proměnných. V tomto případě byla platnost všech nadefinovaných vazeb neomezená. Nabízí se tedy možnost explicitně omezit platnost některých vazeb jen na rozsah určité části programu, například na tělo jedné procedury. V definovaném jazyce za tímto účelem použijeme následující konkrétní a abstraktní syntaxi: <exp> ::= <var> := <exp> during <exp> dynassign (var exp body) Efekt příkazu var := exp during body je takový, že v průběhu vyhodnocování body dočasně přiřadí proměnné var hodnotu exp a po vyhodnocení body vrátí proměnné var její původní hodnotu. Příklad Interpret s dynamickým přiřazením (define eval-exp (lambda (exp env) (variant-case exp (lit (datum) datum) (varref (var) (cell-ref (apply-env env var))) (app (rator rands) (let ((proc (eval-exp rator env)) (args (eval-rands rands env))) (apply-proc proc args))) (if (test-exp then-exp else-exp) (if (true-value? (eval-exp test-exp env)) (eval-exp then-exp env) (eval-exp else-exp env))) (let (decls body) (let ((vars (map decl->var decls)) (exps (map decl->exp decls))) (let ((new-env (extend-env vars (eval-rands exps env) env))) (eval-exp body new-env)))) (proc (formals body) (make-closure formals body env)) (var-assign (var exp) (cell-set! (apply-env env var) (eval-exp exp env)))
15 (dynassign (var exp body) (let ((a-cell (apply-env env var)) (b-cell (make-cell (eval-exp exp env)))) (cell-swap! a-cell b-cell) (let ((value (eval-exp body env))) (cell-swap! a-cell b-cell) value))) (else (error "Invalid abstract syntax: " exp))))) (define apply-proc (lambda (proc args) (variant-case proc (prim-proc (prim-op) (apply-prim-op prim-op args)) (closure (formals body env) (eval-exp body (extend-env formals (map make-cell args) env))) (else (error "Invalid procedure: " proc))))) Vlastnosti a porovnání obou metod Asi nejběžnějším využitím obou metod je přesměrování vstupně-výstupních operací, případně zpracování výjimek ve většině programovacích jazyků. Dynamické přiřazení přitom odstraňuje většinu obtíží, které sebou přináší použití dynamického rozsahu platnosti proměnných. Například lze provádět α-konverze. Výhodou dynamického přiřazení je i to, že je lze využít i v lexikálně zaměřených jazycích, ve kterých rozhodně nelze využít dynamického rozsahu platnosti proměnných. Ovšem, na druhou stranu, dynamické přiřazení sdílí problémy ostatních forem přiřazení. Kupříkladu procedury se nechovají funkcionálně: Výsledky, které vracejí, nemusejí záviset pouze na hodnotách jejich parametrů
16 2 Předávání parametrů 2.1 Podpora polí Mnoho programovacích jazyků podporuje datové struktury skládající se z mnoha prvků, jako jsou například pole nebo záznamy. Takovéto struktury nazýváme agregáty. Tyto typy bývají v paměti obvykle uloženy jako souvislý blok, obsahující všechny elementy této struktury. Pokud je agregát předáván do procedury, je obvykle předáván pouze ukazatel na první buňku příslušného bloku paměti. Tomuto přístupu říkáme nepřímá reprezentace, protože hodnoty agregátu následně nejsou získávány přímo, ale přes ukazatel. Volaná procedura a část programu, ze které je tato procedura volána, používají stejný úsek paměti. Tedy, pokud procedura provede nějaké změny v hodnotách agregátu, projeví se tyto změny následně i v kódu, který tuto proceduru vyvolal. I do našeho jazyka teď přidáme podporu polí s následující konkrétní a abstraktní syntaxí: <form> ::= definearray <var> [<exp>] definearray (var dim-exp) <exp> ::= letarray <arrdcls> in <exp> letarray (arraydecls body) <arrexp> [<exp>] arrayref (array index) <arrexp> [<exp>] := <exp> arrayassign (array index exp) <arrexp> ::= <exp> <arrdcls> ::= <arrdcl> {; <arrdcl>} * <arrdcl> ::= <var> [<exp>] decl (var exp) Pole je sekvence buněk obsahujících vyjadřované hodnoty, což lze vyjádřit takto: Pole = buňka * (vyjadřovaná hodnota) Jelikož náš definující jazyk nepodporuje pole, budeme je implementovat pomocí vektorů, které také poskytují sekvence proměnlivých elementů. Indexování polí bude řešeno tak, že první prvek má vždy index nula. Vyjadřované hodnoty v definovaném jazyce zůstanou i po přidání polí stále reprezentovány pomocí buněk obsahujících vyjadřované hodnoty: Příklad Abstraktní datový typ pole Vyjadřovaná hodnota = číslo + procedura + pole Označovaná hodnota = buňka (vyjadřovaná hodnota) (define-record aggregate (vector)) (define make-array (lambda (dimension) (make-aggregate (make-vector dimension)))) (define array? aggregate?) (define array-ref (lambda (aray index) (vector-ref (aggregate->vector array) index)))
17 (define array-set! (lambda (array index value) (vector-set! (aggrefate->vector array) index value))) (define array-copy (lambda (array) (make-aggregate (list->vector (vector->list (aggregate->vector array)))))) Příklad Interpret s podporou polí (define eval-exp (lambda (exp env) (variant-case exp (lit (datum) datum) (varref (var) (denoted->expressed (apply-env env var))) (app (rator rands) (apply-proc(eval-rator rator env) (eval-rands rands env))) (if (test-exp then-exp else-exp) (if (true-value? (eval-exp test-exp env)) (eval-exp then-exp env) (eval-exp else-exp env))) (proc (formals body) (make-closure formals body env)) (varassign (var exp) (denoted-value-assign! (apply-env env var) (eval-exp exp env))) (letarray (arraydecls body) (eval-exp body (extend-env (map decl->var array decls) (map (lambda (decl) (do-letarray (eval-exp (decl->exp decl) env))) arraydecls) env))) (arrayref (array index) (array-ref (eval-array-exp array env) (eval-exp index env))) (arrayassign (array index exp) (array-set! (eval-array-exp array env) (eval-exp index env) (eval-exp exp env))) (else (error "Invalid abstract syntax: " exp))))) (define apply-proc (lambda (proc args) (variant-case proc (prim-proc (prim-op) (apply-prim-op prim-op args)) (closure (formals body env) (eval-exp body (extend-env formals (map make-cell args) env))) (else (error "Invalid procedure: " proc))))) (define eval-rator (lambda (rands env) (eval-exp rator env))) (define eval-rands (lambda (rands env) (map (lambda (rand) (eval-rand rand env)) rands))) (define eval-rand
18 (lambda (exp env) (expressed->denoted (eval-exp exp env)))) (define apply-proc (lambda (proc args) (variant-case proc (prim-proc (prim-op) (apply-prim-op prim-op (map denoted->expressed args))) (closure (formals body env) (eval-exp body (extend-env formals args env))) (else (error "Invalid procedure: " proc))))) Interpret uvedený v předchozím příkladu neobsahuje definice některých procedur. V závislosti na realizaci těchto definicí je možné specifikovat chování interpretu při předávání polí. Definice těchto procedur pro nepřímé předávání polí jsou uvedeny v následujícím příkladu. Příklad Definice pomocných procedur pro pro nepřímé předávání polí (define denoted->expressed cell-ref) (define denoted-value-assign! cell-set!) (define do-letarray (compose make-cell make-array)) (define eval-array-exp eval exp) (define expressed->denoted make-cell) Pokud potřebujeme, aby interpret prováděl přímé předávání polí (předávání hodnotou), můžeme tyto procedury definovat, jak ukazuje následující příklad. Příklad Definice některých pomocných procedur pro přímé předávání polí (define denoted->expressed (lambda (den-val) (let ((exp-val (cell-ref den-val))) (if (arrray? exp-val) (array-copy exp-val) exp-val)))) (define eval-array-exp (lambda (exp env) (variant-case exp (variant-case exp (varref (var) (let ((exp-val (cell-ref (apply-env env var)))) (if (array? exp-val) exp-val (error "expecting an array: " exp-val)))) (else (eval-exp exp env))))) V uvedeném modelu je realizováno předávání parametrů hodnotou. Každý formální parametr je navázán na buňku obsahující kopii sekvence hodnot původního pole. Jak je patrné z příkladu, je kopírování obsahu prováděno pouze při předávání polí. Předpokládá se totiž, že definující jazyk implicitně používá přímou reprezentaci předávání všech proměnných kromě polí (ta samozřejmě nejsou implicitně podporována vůbec)
19 2.2 Předávání parametrů odkazem Při programování často nastává situace, kdy potřebujeme, aby se změny, které provede volaná procedura ve svých parametrech, projevily i v části programu, ze které byla tato procedura volána. Jinými slovy, aby procedura mohla ve svých prametrech předávat návratové hodnoty. Toho může být dosaženo použitím jiné techniky předávání prametrů, která spočívá v předávání referencí na proměnné, nikoliv jejich vyjadřovaných hodnot. Tento pirincip předávání parametrů je známý jako předávání odkazem. Obecně platí, že tímto způsobem lze jako parametry předávat pouze proměnné, popřípadě jiné datové struktury, na které lze získat referenci do paměti. V některých jazycích je však možné použít předávání odkazem i pro zcela jiné datové struktury (například aplikace). Mechanizmus předávání je pak řešen tak, že hodnota daného operandu je uložena do nové paměťové buňky a její adresa je předána volané proceduře. Přiřazení do takového prametru uvnitř procedury pak ale samozřejmě nemá žádný efekt v rámci volajícího kódu. Zajímavý je případ, kdy dva parametry předávané odkazem odkazují na shodnou paměťovou buňku, jak demonstruje následující příklad. Příklad Dva parametry odkazující na stejnou buňku paměti let b = 3: p = proc (x, y) begin x := 4; y end in p(b, b); Jelikož oba parametry procedury p odkazují na stejnou buňku paměti (proměnná b), způsobí přiřazení x := 4 zároveň přiřazení do y, čímž dojde k přepsání jeho původní hodnoty 3. Výsledek volání procedury p(b, b) je tedy 8 a nikoliv 7, jak by se mohlo na první pohled zdát. Fenomén demonstrovaný v předchozím příkladu je známý pod pojmem aliasing a je velmi nebezpečný, neboť jej nelze jednoduše automaticky detekovat a pravděpodobnost jeho přehlédnutí v programu je vysoká. Jedinou možností detekce jsou náročné run-time testy. Jak budeme modelovat předávání odkazem? Vodítkem nám bude to, že označované hodnoty volající části programu a volané procedury jsou shodné. Tedy, pokud operand bude proměnná, můžeme předat její vazbu přímo do procedury namísto kopírování její hodnoty do nové buňky. Změníme tedy pravidlo gramatiky našeho jazyka na a zároveň změníme proceduru eval-rand takto: <operand> ::= <exp> <operand> ::= <varref>
20 Příklad Procedura eval-rand pro předávání parametrů odkazem (define eval-rand (lambda (rand env) (variant-case rand (varref (var) (apply-env env var)) (else error "Invalid operand: " rand))))) Situace se poněkud zkomplikuje v okamžiku, kdy přidáme požadavek na předávání jednotlivých prvků polí odkazem. Až do této chvíle jsme při předávání polí odkazem předpokládali předání ukazatele na první prvek pole. V typické implementaci se jedná pouze o předání ukazatele na příslušný prvek pole. Náš definující jazyk však nedokáže získat ukazatel na libovolný prvek vektorového elementu. Proto budeme jednotlivé prvky pole reprezentovat jako záznamy, jež budou obsahovat pole a index tohoto prvku uvnitř pole. (define-record ae (array index)) Obecně je tedy jakákoliv L-hodnota v tomto programovacím jazyce buď buňka paměti nebo prvek pole. V každém případě L-hodnota představuje vyjadřovanou hodnotu, což můžeme zapsat takto: L-hodnota = buňka (vyjadřovaná hodnota) + prvek pole (vyjadřovaná hodnota) Označovaná hodnota = L-hodnota Nyní přidáme do našeho jazyka možnost předávání odkazem pro libovolné výrazy, přičemž jejich hodnoty budou předávány hodnotou v nových paměťových buňkách s následující konkrétní a abstraktní syntaxí: <operand> ::= <varref> <array-exp> [<exp>] arrayref (array index) <exp> Abychom získali interpret provádějící předávání parametrů odkazem, provedeme modifikaci interpretu pro předávání hodnotou a modifikujeme pomocné procedury. V souladu s uvedenou gramatikou pro operandy bude eval-rand obsahovat tři větve. Pokud operand bude proměnná, případně reference na pole, bude do volané procedury předána korespondující L-hodnota. V opačném případě bude výraz vyhodnocen, zkopírován do nové paměťové buňky a předán hodnotou. Jelikož jsme změnili množinu označovaných hodnot, potřebujeme změnit procedury, které s nimi pracují (denoted->expressed a denoted-value-assign!). Příklad Pomocné procedury pro předávání parametrů odkazem s nepřímým předáváním polí (define eval-rand (lambda (rand env) (variant-case rand (varref (var) (apply-env env var)) (arrayref (array index) (make-ae (eval-array-exp array env) (eval-exp index env))) (else (make-cell (eval-exp rand env)))))) (define denoted->expressed (lambda (den-val)
21 (cond ((cell? den-val) (cell-ref den-val)) ((ae? den-val) (array-ref (ae->array den-val) (ae->index den-val))) (else (error "Can t dereference denoted value: " den-val))))) (define denoted-value-assign! (lambda (den-val val) (cond ((cell? den-val) (cell-set! den-val val)) ((ae? den-val) (array-set! (ae->array den-val) (ae->index den-val) val)) (else (error "Can t assign to denoted value: " den-val))))) S kombinací přímého a nepřímého předávání parametrů se v programovacích jazycích setkáváme velice často - například při předávání pole jako var parametru v Pascalu. 2.3 Předávání hodnotou-odkazem a předávání výsledkem Technika předávání hodnotou-odkazem v sobě kombinuje efektivnost metody předávání hodnotou s možností navrácení výsledku jako u metody předávání odkazem. Trik pro splnění těchto vlastností je poměrně jednoduchý. Při volání se parametr nejprve zkopíruje do nové paměťové buňky, v těle procedury se používá jako by byl předávaný hodnotou a v okamžiku návratu je jeho konečná hodnota zkopírována na místo původního parametru (původní hodnota je přepsána). Přístup k parametrům v těle procedury je velmi rychlý (stejně jako při použití předávání hodnotou), ovšem režie při vyvolání a ukončení procedury je vysoká, (také stejně jako při předávání hodnotou), neboť probíhá kopírování paměťových buněk. Díky tomu se tento přístup jeví jako výhodný v případě, že potřebujeme mít možnost navracet v parametrech výsledky a zároveň se jednotlivé parametry v těle procedury často používají (například v těle cyklu). V případě malého počtu použítí se jeví jako výhodnější použití metody předávání odkazem. Existuje však ještě jeden důvod, proč preferovat předávání hodnotou-odkazem před předáváním odkazem. Předávání hodnotou-odkazem je odolné vůči vzniku aliasingu (každý parametr je uložen v jiné paměťové buňce), což zvyšuje odolnost programu vůči skrytým chybám. Technika předávání parametrů výsledkem je použitelná pouze pokud daným parametrem nepotřebujeme předávat data do procedury, ale potřebujeme je v něm vrátit. Jedná se o jednoduchou variantu předávání hodnotou-odkazem, ve které je lokální L-hodnota parametru neinicializovaná. Předávání hodnotou, předávání hodnotou-odkazem a předávní výsledkem bývají někdy souhrnně označovány jako předávání kopií, neboť při vyvolání procedury se vždy kopíruje hodnota proměnné předávané jako parametr. 2.4 Vyjadřované nebo označované hodnoty? Jazyky, které jsme zatím vytvořili, stejně jako náš definující jazyk měly bohatou množinu vyjadřovaných hodnot, ale pouze jediný druh ozančované hodnoty - buňky obsahující vyjadřované
22 hodnoty. Mít v jazyce bohatou množinu vyjadřovaných hodnot je velice důležité, neboť hlavní cestou, kterou se vrací vypočtené informace, je návratová hodnota procedury - označovaná hodnota. V tradičních imperativních jazycích se však výrazy vyskytují především v přiřazovacích příkazech, takže množina vyjadřovaných hodnot zhruba koresponduje s množinou hodnot, které mohou být uloženy v paměťových lokacích. Obvykle je tedy velmi malá, zatímco množina označovaných hodnot bývá obvkle velmi bohatá. Například v Pascalu jsou vyjadřovanými hodnotami skaláry jako jou integery nebo znaky, zatímco označované hodnoty jsou procedury a pole. Nyní zkusíme tento princip implementovat do našeho interpretu. Nový jazyk bude mít nejjednodušší možnou množinu vyjadřovaných hodnot: Vyjadřovaná hodnota = číslo zato množinu označovaných hodnot vytvoříme poněkud bohatší: Označovaná hodnota = L-hodnota + pole + procedura Pole a procedury tedy nyní budou označované hodnoty, nikoliv vyjadřované. Tato změna nezpůsobí vážnější problémy u polí, neboť jsou vytvářena pomocí letarray, ale u procedur je situace již poněkud složitější. Fakt, že procedury jsou vyjadřované hodnoty, je začleněn přímo v syntaxi jazyka a tím i v interpretu. Procedury jsou totiž vytvářeny jako vyjadřované hodnoty pomocí proc a zároveň navráceny jako vyjadřované hodnoty v okamžiku, kdy eval-exp vyhodnotí operátorovou část aplikace. Nejdříve tedy musíme změnit syntaxi našeho jazyka. Procedura nebo pole budou nyní moci existovat pouze jako vazba na proměnnou a zároveň potřebujeme zavést nějakou formu jako let, která umožní deklaraci proměnných bez použití aplikace procedury. Z původní gramatiky tedy odstraníme pravidla <exp> ::= proc <varlist> <exp> proc (formals body) <operator> ::= <exp> <array-exp> ::= <exp> a nahradíme je následujícími pravidly <exp> ::= letrecproc <procdecls> in letrecproc (procdecls <exp> body) local <decls> in <exp> local (decls body) operator ::= <varref> <array-exp> ::= <varref> Pro předávání parametrů do procedur použijeme techniku předávání odkazem. K tomu využijeme interpret z kapitol 2.1 až 2.2 a provedeme potřebné modifikace. Příklad Interpret s procedurami a poli jako označovanými hodnotami (define eval-exp (lambda (exp env) (variant-case exp (lit (datum) datum) (varref (var) (denoted->expressed (apply-env env var)))
23 (app (rator rands) (apply-proc(eval-rator rator env) (eval-rands rands env))) (if (test-exp then-exp else-exp) (if (true-value? (eval-exp test-exp env)) (eval-exp then-exp env) (eval-exp else-exp env))) (letproc (procdecls body) (let ((vars (map procdecl->var procdecls)) (closures (map (lambda (decl) (make-closure (procdecl->formals decl) (procdecl->body decl) env)) procdecls))) (let ((new-env (extend-env vars closures env))) (eval-exp body new-enw)))) (local (decls body) (let ((vars (map decl->var decls)) (exps (map decl->exp decls))) (let ((new-env (extend-env vars (map (lambda (exp) (make-cell (eval-exp exp env))) exps) env))) (eval-exp body new-env)))) (var-assign (var exp) (denoted-value-assign! (apply-env env var) (eval-exp exp env))) (letarray (arraydecls body) (eval-exp body (extend-env (map decl->var arraydecls) (map (lambda (decl) (do-letarray (eval-exp (decl->exp decl) env))) arraydecls) env))) (arrayref (array index) (array-ref (eval-array-exp array env) (eval-exp index env))) (arrayassign (array index exp) (array-set! (eval-array-exp array env) (eval-exp index env) (eval-exp exp env))) (else (error "Invalid abstract syntax: " exp))))) (define eval-rator (lambda (rator env) (let ((den-val (apply-env env (varref->var rator)))) (if (closure? den-val) den-val (denoted->expressed den-val))))) V interpretu byly provedeny dvě změny. První se týká procedury eval-rator, která původně používala eval-exp. Nyní používá apply-env, neboť rator je reference na proměnnou. Druhou změnou je nová konstrukce letproc. Kód letproc vytvoří seznam uzávěrů a potom vyhodnotí tělo procedury v novém prostředí, ve kterém je každé ze jmen vázáno k odpovídajícímu uzávěru
24 Jelikož se změnily množiny označovaných a vyjadřovaných hodnot, musíme změnit také pomocné procedury uvedené v kapitole 2.2, které pracují s označovanými hodnotami. Procedury denoted->expressed a denoted-value-assign! mohou zůstat bez změny, neboť již obsahují testy zajišťující kontrolu, zda jsou dereferovány či měněny pouze platné L-hodnoty. Podobně mohou zůstat bez změn i expressed->denoted a eval-rand. Příklad Pomocné procedury pro předávání parametrů odkazem s poli jako označovanými hodnotami (define denoted->expressed (lambda (den-val) (cond ((cell? den-val) (cell-ref den-val)) ((ae? den-val) (array-ref (ae->array den-val) (ae->index den-val))) (else (error "Can t dereference denoted value: " den-val))))) (define denoted-value-assign! (lambda (den-val val) (cond ((cell? den-val) (cell-set! den-val val)) ((ae? den-val) (array-set! (ae->array den-val) (ae->index den-val) val)) (else (error "Can t assign to denoted value: " den-val))))) (define do-letarray make-array) (define eval-array-exp (lambda (array-exp env) (apply-env env (varref->var array-exp)))) (define eval-rand (lambda (rand env) (variant-case rand (varref (var) (apply-env env var)) (arrayref (array index) (make-ae (eval-array-exp array env) (eval-exp index env))) (else (make-cell (eval-exp rand env)))))) (define expressed->denoted make-cell) V této kapitole jsme se pouze lehce dotkli různých struktur hodnot v programovacích jazycích. Studium označovaných a vyjadřovaných hodnot jazyka nám umožní lépe proniknout do jeho vnitřní struktury. Struktura hodnot v jazyce určuje velkou měrou jeho vyjadřovací sílu a efektivnost a ovlivňuje implementační strategie. Například, pokud procedury nejsou vyjadřovanými hodnotami, není možné použít většinu funkcionálních technik. Na druhou stranu, pokud jsou procedury vyjadřovanými hodnotami, musí být alokovány na hromadě, což je obecně méně efektivní, než alokace na zásobníku
25 2.5 Předávání jménem a předávání s vyhodnocením při potřebnosti Výrazy lambda kalkulu mohou být vyhodnocovány použitím β-redukcí. V tomto modelu jsou procedury volány vykonáním jejich těla poté, co jsou operandy substituovány pro každou referenci za odpovídající proměnnou. Tato substituce může vyžadovat α-konverzi, aby se zabránilo případnému navázání proměnných, které jsou v operandech volné. Takovéto přepisovací techniky, které vyžadují manipulaci s textem programu v průběhu jeho vyhodnocování, bývají intenzivně využívány při teoretických studiích programovacích jazyků. Pro praktické využití však většinou bývají velmi neefektivní. β-redukce má jednu zajímavou vlastnost, která má občas i praktický význam a není možná při použití technik předávání parametrů uvedených dříve - umožňuje odložit vyhodnocení operandů (použitím normálního pořadí vyhodnocení) až do okamžiku, kdy budou skutečně potřeba. To může zabránit zbytečnému, případně nekonečnému, vyhodnocování, ovšem za cenu opakovaného vyhodnocování každé reference v případě, že tělo funkce obsahuje více referencí na jeden parametr. Aby bylo možné dosáhnout odložení vyhodnocení operandu bez nutnosti přepsat program, je možné předávat jako parametry reference na abstraktní syntaktické stromy (případně na kompilovaný kód) jednotlivých operandů. Pak je ale nutné zajistit, aby nemohlo dojít k nechtěnému navázání původně volných proměnných ve volané proceduře. Tento problém lze vyřešit poměrně jednoduše - uzavřít operandy v prostředí, ze kterého je procedura volána. Toho dosáhneme zformováním datové struktury, která bude obsahovat textovou reprezentaci operandu a také vazby všech proměnných, které jsou v tomto operandu volné. Takovéto uzávěry budeme nazývat odložené výpočty (thunks). Technika předávání parametrů využívající zpožděné vyhodnocování všech argumentů s využitím odložených výpočtů a provádějící vyhodnocení každého operandu (tedy i opakované, pokud je daný parametr použit vícekrát) v okamžiku, kdy je potřeba, se nazývá předávání jménem. Nyní vytvoříme interpret používající volání jménem a nepřímé předávání parametrů. Nejprve určíme vyjadřované a označované hodnoty. Vyjdeme z interpretu uvedeného v kapitole 2.1. Množinu vyjadřovaných hodnot ponecháme beze změny: Vyjadřovaná hodnota = číslo + procedura + pole Množina popisovaných hodnot ale nyní musí obsahovat i odložené výpočty, které zapouzdřují každý operand i s jeho prostředím. Jelikož se formální parametr může vyskytovat na levé straně přiřazení, vyvolání odloženého výpočtu musí vracet L-hodnotu, což zapíšeme jako odložený výpočet = () L-hodnota ve významu, že odložený výpočet je procedura bez parametrů, která vrací L-hodnotu, pokud je zavolána. Odložený výpočet obsahující operand a prostředí budeme reprezentovat následujícím záznamem: (define-record thunk (exp env))
26 Stejně jako v případě předávání odkazem, bude množian L-hodnot obsahovat i pole: L-hodnota = buňka (vyjadřovaná hodnota) + prvek pole (vyjadřovaná hodnota) Jelikož množina L-hodnot zůstala stejná, můžeme i většinu pomocných procedur ponechat beze změny. Protože použití mechanizmu odložených výpočtů i pro lokální proměnné procedur by bylo značně neefektivní, budeme je reprezentovat obvyklým způsobem. Označované hodnoty tedy budou buď L-hodnoty nebo odložené výpočty: Označovaná hodnota = L-hodnota + odložený výpočet Interpret, který nyní vytvoříme bude obsahovat jednu podstatnou změnu oproti interpretu z kapitoly 2.1. Procedura eval-rands nebude vyhodnocovat operandy, ale bude je zapouzdřovat do odložených výpočtů (záznamů thunks). Jednotlivé odložené výpočty budou vyhodnocovány až v proceduře. Příklad Interpret s předáváním prametrů jménem (define eval-exp (lambda (exp env) (variant-case exp (local (decls body) (let ((vars (map decl->var decls)) (exps (map decl->wxp decls))) (let ((new-env (extend-env vars (map (lambda (exp) (make-cell (eval-exp exp env))) exps) env))) (eval-exp body new-env)))) (lit (datum) datum) (varref (var) (denoted->expressed (apply-env env var))) (app (rator rands) (apply-proc(eval-rator rator env) (eval-rands rands env))) (if (test-exp then-exp else-exp) (if (true-value? (eval-exp test-exp env)) (eval-exp then-exp env) (eval-exp else-exp env))) (proc (formals body) (make-closure formals body env)) (varassign (var exp) (denoted-value-assign! (apply-env env var) (eval-exp exp env))) (letarray (arraydecls body) (eval-exp body (extend-env (map decl->var arraydecls) (map (lambda (decl) (do-letarray (eval-exp (decl->exp decl) env))) arraydecls) env))) (arrayref (array index) (array-ref (eval-array-exp array env) (eval-exp index env))) (arrayassign (array index exp) (array-set!
Čtvrtek 8. prosince. Pascal - opakování základů. Struktura programu:
Čtvrtek 8 prosince Pascal - opakování základů Struktura programu: 1 hlavička obsahuje název programu, použité programové jednotky (knihovny), definice konstant, deklarace proměnných, všechny použité procedury
Sdílení dat mezi podprogramy
Sdílení dat mezi podprogramy Datové objekty mohou být mezi podprogramy sdíleny pomocí ne-lokálních referenčních prostředí, která jsou vytvářena na základě æ explicitních modifikací (formální parametry
Programovací jazyk Pascal
Programovací jazyk Pascal Syntaktická pravidla (syntaxe jazyka) přesná pravidla pro zápis příkazů Sémantická pravidla (sémantika jazyka) pravidla, která každému příkazu přiřadí přesný význam Všechny konstrukce
Algoritmizace a programování
Algoritmizace a programování Řídicí struktury jazyka Java Struktura programu Příkazy jazyka Blok příkazů Logické příkazy Ternární logický operátor Verze pro akademický rok 2012/2013 1 Struktura programu
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
Denotační sémantika programovacího jazyka doc. Dr. Ing. Miroslav Beneš katedra informatiky, A-1007 59 732 4213 Obsah přednášky Princip denotační sémantiky Sémantické funkce Výrazy Příkazy Vstup a výstup
Struktura programu v době běhu
Struktura programu v době běhu Miroslav Beneš Dušan Kolář Struktura programu v době běhu Vztah mezi zdrojovým programem a činností přeloženého programu reprezentace dat správa paměti aktivace podprogramů
PARADIGMATA PROGRAMOVÁNÍ 2 PŘÍSLIBY A LÍNÉ VYHODNOCOVÁNÍ
KATEDRA INFORMATIKY, PŘÍRODOVĚDECKÁ FAKULTA UNIVERZITA PALACKÉHO, OLOMOUC PARADIGMATA PROGRAMOVÁNÍ 2 PŘÍSLIBY A LÍNÉ VYHODNOCOVÁNÍ Slajdy vytvořili Vilém Vychodil a Jan Konečný (KI, UP Olomouc) PP 2, Lekce
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.
Informatika 10. 9. 2013 Jméno a příjmení Rodné číslo 1) Napište algoritmus pro rychlé třídění (quicksort). 2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus
Vyučovací hodina. 1vyučovací hodina: 2vyučovací hodiny: Opakování z minulé hodiny. Procvičení nové látky
Vyučovací hodina 1vyučovací hodina: Opakování z minulé hodiny Nová látka Procvičení nové látky Shrnutí 5 min 20 min 15 min 5 min 2vyučovací hodiny: Opakování z minulé hodiny Nová látka Procvičení nové
Základní pojmy. Úvod do programování. Základní pojmy. Zápis algoritmu. Výraz. Základní pojmy
Úvod do programování Michal Krátký 1,Jiří Dvorský 1 1 Katedra informatiky VŠB Technická univerzita Ostrava Úvod do programování, 2004/2005 Procesor Procesorem je objekt, který vykonává algoritmem popisovanou
Implementace LL(1) překladů
Překladače, přednáška č. 6 Ústav informatiky, FPF SU Opava sarka.vavreckova@fpf.slu.cz Poslední aktualizace: 30. října 2007 Postup Programujeme syntaktickou analýzu: 1 Navrhneme vhodnou LL(1) gramatiku
1. D Y N A M I C K É DAT O V É STRUKTUR Y
1. D Y N A M I C K É DAT O V É STRUKTUR Y Autor: Petr Mik Abychom se mohli pustit do dynamických datových struktur, musíme se nejdřív podívat na datový typ ukazatel. 1. D AT O V Ý TYP U K A Z AT E L Datové
PB161 Programování v jazyce C++ Přednáška 4
PB161 Programování v jazyce C++ Přednáška 4 Přetěžování funkcí Konstruktory a destruktory Nikola Beneš 9. října 2017 PB161 přednáška 4: přetěžování funkcí, konstruktory, destruktory 9. října 2017 1 / 20
Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007
Úvod do programovacích jazyků (Java) Michal Krátký Katedra informatiky VŠB Technická univerzita Ostrava Úvod do programovacích jazyků (Java), 2006/2007 c 2006 Michal Krátký Úvod do programovacích jazyků
Více o konstruktorech a destruktorech
Více o konstruktorech a destruktorech Více o konstruktorech a o přiřazení... inicializovat objekt lze i pomocí jiného objektu lze provést přiřazení mezi objekty v původním C nebylo možné provést přiřazení
int ii char [16] double dd název adresa / proměnná N = nevyužito xxx xxx xxx N xxx xxx N xxx N
Struktura (union) - struktura a union jsou složené typy, které "v sobě" mohou obsahovat více proměnných - struktura obsahuje v každém okamžiku všechny své proměnné, union obsahuje (=je "aktivní") pouze
přetížení operátorů (o)
přetížení operátorů (o) - pro vlastní typy je možné přetížit i operátory (tj. definovat vlastní) - pro definici slouží klíčové slovo operator následované typem/znakem operátoru - deklarace pomocí funkčního
Pascal. Katedra aplikované kybernetiky. Ing. Miroslav Vavroušek. Verze 7
Pascal Katedra aplikované kybernetiky Ing. Miroslav Vavroušek Verze 7 Proměnné Proměnná uchovává nějakou informaci potřebnou pro práci programu. Má ve svém oboru platnosti unikátní jméno. (Připadne, musí
PODPROGRAMY PROCEDURY A FUNKCE
PODPROGRAMY PROCEDURY A FUNKCE Programy bez podprogramů Příklady: a) Napište program, který na obrazovku nakreslí čáru složenou ze znaků pomlčka. program Cara; b) Napište program, který na obrazovku nakreslí
Algoritmizace prostorových úloh
INOVACE BAKALÁŘSKÝCH A MAGISTERSKÝCH STUDIJNÍCH OBORŮ NA HORNICKO-GEOLOGICKÉ FAKULTĚ VYSOKÉ ŠKOLY BÁŇSKÉ - TECHNICKÉ UNIVERZITY OSTRAVA Algoritmizace prostorových úloh Datové struktury Daniela Szturcová
PŘETĚŽOVÁNÍ OPERÁTORŮ
PŘETĚŽOVÁNÍ OPERÁTORŮ Jazyk C# podobně jako jazyk C++ umožňuje přetěžovat operátory, tj. rozšířit definice některých standardních operátorů na uživatelem definované typy (třídy a struktury). Stejně jako
Konstruktory a destruktory
Konstruktory a destruktory Nedostatek atributy po vytvoření objektu nejsou automaticky inicializovány hodnota atributů je náhodná vytvoření metody pro inicializaci, kterou musí programátor explicitně zavolat,
Paradigmata programování 1
Paradigmata programování 1 Explicitní aplikace a vyhodnocování Vilém Vychodil Katedra informatiky, PřF, UP Olomouc Přednáška 6 V. Vychodil (KI, UP Olomouc) Explicitní aplikace a vyhodnocování Přednáška
Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody
Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody Dynamická alokace paměti Jazyky C a C++ poskytují programu možnost vyžádat si část volné operační paměti pro
Da D to t v o é v ty t py IB111: Datové typy
Datové typy IB111: Datové typy Data a algoritmizace jaká data potřebuji pro vyřešení problému? jak budu data reprezentovat? jaké operaci s nimi potřebuji provádět? Navržení práce s daty je velice důležité
Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě
Metody přidělování paměti Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě Důležitá hlediska jazykových konstrukcí: Dynamické typy Dynamické
PODOBÁ SE JAZYKU C S NĚKTERÝMI OMEZENÍMI GLOBÁLNÍ PROMĚNNÉ. NSWI162: Sémantika programů 2
PI JE JEDNODUCHÝ IMPERATIVNÍ PROGRAMOVACÍ JAZYK OBSAHUJE PODPORU ANOTACÍ NEOBSAHUJE NĚKTERÉ TYPICKÉ KONSTRUKTY PROGRAMOVACÍCH JAZYKŮ JAKO JSOU REFERENCE, UKAZATELE, GLOBÁLNÍ PROMĚNNÉ PODOBÁ SE JAZYKU C
Tabulka symbolů. Vazba (binding) Vazba - příklad. Deklarace a definice. Miroslav Beneš Dušan Kolář
Vazba (binding) Tabulka symbolů Miroslav Beneš Dušan Kolář vazba = spojení mezi entitou a vlastností okamžik vazby (binding time) při návrhu jazyka při implementaci jazyka během překladu/spojování/zavádění
7 Formátovaný výstup, třídy, objekty, pole, chyby v programech
7 Formátovaný výstup, třídy, objekty, pole, chyby v programech Studijní cíl Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost formátovanému výstupu,
Lokální definice (1) plocha-kruhu
Lokální definice (1) syntaxe: (local (seznam definic) výraz) definice jsou dostupné pouze uvnitř příkazu local příklad: (local ( (define Pi 3.1415926) (define (plocha-kruhu r) (* Pi r r)) ) (plocha-kruhu
FUNKCIONÁLNÍ A LOGICKÉ PROGRAMOVÁNÍ 3. CVIČENÍ
FUNKCIONÁLNÍ A LOGICKÉ PROGRAMOVÁNÍ 3. CVIČENÍ 2011 Jan Janoušek MI-FLP Evropský sociální fond Praha & EU: Investujeme do vaší budoucnosti Page 1 of 6 Cviceni 3 Obsah seznamy, cons-buňka, car, cdr, first,
Úvod do programovacích jazyků (Java)
Úvod do programovacích jazyků (Java) Michal Krátký Katedra informatiky VŠB Technická univerzita Ostrava Úvod do programovacích jazyků (Java), 2007/2008 c 2006 2008 Michal Krátký Úvod do programovacích
Paradigmata programování 1
Paradigmata programování 1 Vytváření abstrakcí pomocí procedur Vilém Vychodil Katedra informatiky, PřF, UP Olomouc Přednáška 2 V. Vychodil (KI, UP Olomouc) Vytváření abstrakcí pomocí procedur Přednáška
Základní datové struktury
Základní datové struktury Martin Trnečka Katedra informatiky, Přírodovědecká fakulta Univerzita Palackého v Olomouci 4. listopadu 2013 Martin Trnečka (UPOL) Algoritmická matematika 1 4. listopadu 2013
8 Třídy, objekty, metody, předávání argumentů metod
8 Třídy, objekty, metody, předávání argumentů metod Studijní cíl Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost třídám a objektům, instančním
Lineární spojový seznam (úvod do dynamických datových struktur)
Lineární spojový seznam (úvod do dynamických datových struktur) Jan Hnilica Počítačové modelování 11 1 Dynamické datové struktury Definice dynamické struktury jsou vytvářeny za běhu programu z dynamicky
DUM 06 téma: Tvorba makra pomocí VBA
DUM 06 téma: Tvorba makra pomocí VBA ze sady: 03 tematický okruh sady: Tvorba skript a maker ze šablony: 10 Algoritmizace a programování určeno pro: 4. ročník vzdělávací obor: 18-20-M/01 Informační technologie
Paradigmata programování 1
Paradigmata programování 1 Tečkové páry, symbolická data a kvotování Vilém Vychodil Katedra informatiky, PřF, UP Olomouc Přednáška 4 V. Vychodil (KI, UP Olomouc) Tečkové páry, symbolická data a kvotování
Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě
Metody přidělování paměti Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě Důležitá hlediska jazykových konstrukcí: Dynamické typy Dynamické
Unity a Objekty (NMIN102) RNDr. Michal Žemlička, Ph.D.
Unity a Objekty Programování 2 (NMIN102) RNDr. Michal Žemlička, Ph.D. Větší programy Časté problémy: Ve více programech by se nám hodilo využít stejné řešení nějakého podproblému dalo by se vyřešit překopírováním
konstruktory a destruktory (o)
konstruktory a destruktory (o) - slouží k ovlivnění vzniku (inicializace) a zániku (úklid) objektu - základní myšlenkou je, že proměnná by měla být inicializována (nastavena do počátečního stavu) a zároveň
Programování v C++ 2, 4. cvičení
Programování v C++ 2, 4. cvičení statické atributy a metody, konstruktory 1 1 Fakulta jaderná a fyzikálně inženýrská České vysoké učení technické v Praze Zimní semestr 2018/2019 Přehled Přístupová práva
Náznak ukázky syntaxe a sémantiky pro projekt. 1 Syntaktické prvky. Poslední aktualizace: 8.
Jednoduchý interpretační překladač Náznak ukázky syntaxe a sémantiky pro projekt Šárka Vavrečková Ústav informatiky, FPF SU Opava sarka.vavreckova@fpf.slu.cz Poslední aktualizace: 8. ledna 2008 1 Syntaktické
Programování v jazyce C a C++
Programování v jazyce C a C++ Richter 1 Petyovský 2 1. března 2015 1 Ing. Richter Miloslav, Ph.D., UAMT FEKT VUT Brno 2 Ing. Petyovský Petr, UAMT FEKT VUT Brno C++ Stručná charakteristika Nesdíĺı normu
Paralelní programování
Paralelní programování přednášky Jan Outrata únor duben 2011 Jan Outrata (KI UP) Paralelní programování únor duben 2011 1 / 14 Atomické akce dále nedělitelná = neproložitelná jiným procesem izolovaná =
Tematický celek Proměnné. Proměnné slouží k dočasnému uchovávání hodnot během provádění aplikace Deklarace proměnných
Tematický celek 03 3.1 Proměnné Proměnné slouží k dočasnému uchovávání hodnot během provádění aplikace. 3.1.1 Deklarace proměnných Dim jméno_proměnné [As typ] - deklarace uvnitř procedury platí pouze pro
Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu
Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu Ukazatel a dynamické datové struktury v prostředí DELPHI Důležitým termínem a konstrukčním programovým prvkem je typ UKAZATEL. Je to vlastně
Algoritmizace prostorových úloh
INOVACE BAKALÁŘSKÝCH A MAGISTERSKÝCH STUDIJNÍCH OBORŮ NA HORNICKO-GEOLOGICKÉ FAKULTĚ VYSOKÉ ŠKOLY BÁŇSKÉ - TECHNICKÉ UNIVERZITY OSTRAVA Algoritmizace prostorových úloh Datové struktury Daniela Szturcová
Funkcionální programování. Kristýna Kaslová
Funkcionální programování Kristýna Kaslová Historie Alonzo Church (30. léta) Netypovaný lambda kalkul Základ prvních funkcionálních jazyků Jeho konstrukce i v mnoha současných programovacích jazycích (Python)
Programujeme v softwaru Statistica
Programujeme v softwaru Statistica díl druhý Newsletter Statistica ACADEMY Téma: Programování, makra, skripty Typ článku: Návody V tomto článku si ukážeme další možnosti při psaní maker v softwaru Statistica.
MAXScript výukový kurz
MAXScript výukový kurz Díl čtvrtý jazyk MAXScript, část I. Jan Melichar, březen 2008 Jan Melichar (aka JME) strana 1 OBSAH ÚVOD... 4 ZÁKLADNÍ PŘÍKAZY... 5 OPERÁTORY... 6 PROMĚNNÉ... 6 POLE... 7 ZÁVĚREM...
Čtvrtek 3. listopadu. Makra v Excelu. Obecná definice makra: Spouštění makra: Druhy maker, způsoby tvorby a jejich ukládání
Čtvrtek 3. listopadu Makra v Excelu Obecná definice makra: Podle definice je makro strukturovanou definicí jedné nebo několika akcí, které chceme, aby MS Excel vykonal jako odezvu na nějakou námi definovanou
Generování vnitřní reprezentace programu
Generování vnitřní reprezentace programu Miroslav Beneš Dušan Kolář Možnosti překladu Interpretace Okamžité provádění programu Překlad do instrukcí procesoru Závislost na konkrétním typu procesoru Překlad
Paradigmata programování 1
Paradigmata programování 1 Kvazikvotování a manipulace se symbolickými výrazy Vilém Vychodil Katedra informatiky, PřF, UP Olomouc Přednáška 11 V. Vychodil (KI, UP Olomouc) Kvazikvotování, manipulace se
Rekurze. Pavel Töpfer, 2017 Programování 1-8 1
Rekurze V programování ve dvou hladinách: - rekurzivní algoritmus (řešení úlohy je definováno pomocí řešení podúloh stejného charakteru) - rekurzivní volání procedury nebo funkce (volá sama sebe přímo
Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost rozhraním a výjimkám.
13 Rozhraní, výjimky Studijní cíl Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost rozhraním a výjimkám. Doba nutná k nastudování 2 2,5 hodiny
Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15
Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15 KAPITOLA 1 Úvod do programo vání v jazyce C++ 17 Základní pojmy 17 Proměnné a konstanty 18 Typy příkazů 18 IDE integrované vývojové
Reprezentace aritmetického výrazu - binární strom reprezentující aritmetický výraz
Reprezentace aritmetického výrazu - binární strom reprezentující aritmetický výraz (2 + 5) * (13-4) * + - 2 5 13 4 - listy stromu obsahují operandy (čísla) - vnitřní uzly obsahují operátory (znaménka)
1. Od Scheme k Lispu
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
Syntaktická analýza. Implementace LL(1) překladů. Šárka Vavrečková. Ústav informatiky, FPF SU Opava
Implementace LL(1) překladů Ústav informatiky, FPF SU Opava sarka.vavreckova@fpf.slu.cz Poslední aktualizace: 6. ledna 2012 Postup Programujeme syntaktickou analýzu: 1 Navrhneme vhodnou LL(1) gramatiku
Úvod do programovacích jazyků (Java)
Úvod do programovacích jazyků (Java) Michal Krátký Katedra informatiky VŠB Technická univerzita Ostrava Úvod do programovacích jazyků (Java), 2007/2008 c 2006 2008 Michal Krátký Úvod do programovacích
6 Příkazy řízení toku
6 Příkazy řízení toku Studijní cíl Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost příkazům pro řízení toku programu. Pro všechny tyto základní
type Obdelnik = array [1..3, 1..4] of integer; var M: Obdelnik;
Vícerozměrné pole type Obdelnik = array [1..3, 1..4] of integer; var M: Obdelnik; M[2,3] := 3145; - počet indexů není omezen (v praxi obvykle nejvýše tři) - více indexů pomalejší přístup k prvku (počítá
Algoritmizace a programování
Algoritmizace a programování Vyhledávání, vkládání, odstraňování Vyhledání hodnoty v nesetříděném poli Vyhledání hodnoty v setříděném poli Odstranění hodnoty z pole Vkládání hodnoty do pole Verze pro akademický
O datových typech a jejich kontrole
.. O datových typech a jejich kontrole Programovací techniky doc. Ing. Jiří Rybička, Dr. ústav informatiky PEF MENDELU v Brně rybicka@mendelu.cz Typová kontrola Programovací techniky O datových typech
Problém, jehož různé instance je třeba často řešit Tyto instance lze vyjádřit větami v jednoduchém jazyce
Interpreter Interpreter Motivace Problém, jehož různé instance je třeba často řešit Tyto instance lze vyjádřit větami v jednoduchém jazyce Příklad: zda daný textový řetězec odpovídá nějakému vzoru (match)
Maturitní otázky z předmětu PROGRAMOVÁNÍ
Wichterlovo gymnázium, Ostrava-Poruba, příspěvková organizace Maturitní otázky z předmětu PROGRAMOVÁNÍ 1. Algoritmus a jeho vlastnosti algoritmus a jeho vlastnosti, formy zápisu algoritmu ověřování správnosti
24-2-2 PROMĚNNÉ, KONSTANTY A DATOVÉ TYPY TEORIE DATUM VYTVOŘENÍ: 23.7.2013 KLÍČOVÁ AKTIVITA: 02 PROGRAMOVÁNÍ 2. ROČNÍK (PRG2) HODINOVÁ DOTACE: 1
24-2-2 PROMĚNNÉ, KONSTANTY A DATOVÉ TYPY TEORIE AUTOR DOKUMENTU: MGR. MARTINA SUKOVÁ DATUM VYTVOŘENÍ: 23.7.2013 KLÍČOVÁ AKTIVITA: 02 UČIVO: STUDIJNÍ OBOR: PROGRAMOVÁNÍ 2. ROČNÍK (PRG2) INFORMAČNÍ TECHNOLOGIE
Programování v C++, 2. cvičení
Programování v C++, 2. cvičení 1 1 Fakulta jaderná a fyzikálně inženýrská České vysoké učení technické v Praze Zimní semestr 2018/2019 Přehled 1 Operátory new a delete 2 3 Operátory new a delete minule
1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:
1. lekce 1. Minimální program do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme: #include #include int main() { printf("hello world!\n"); return 0; 2.
Skripta ke školení. Základy VBA. vypracoval: Tomáš Herout. tel:
Skripta ke školení Základy VBA vypracoval: Tomáš Herout e-mail: herout@helpmark.cz tel: 739 719 548 2016 Obsah TROCHA TEORIE VBA...2 ZPŮSOB ZÁPISU VE VBA...2 CO JE TO FUNKCE...2 CO JE TO PROCEDURA...2
VÝUKOVÝ MATERIÁL. Bratislavská 2166, 407 47 Varnsdorf, IČO: 18383874 www.vosassvdf.cz, tel. +420412372632 Číslo projektu
VÝUKOVÝ MATERIÁL Identifikační údaje školy Vyšší odborná škola a Střední škola, Varnsdorf, příspěvková organizace Bratislavská 2166, 407 47 Varnsdorf, IČO: 18383874 www.vosassvdf.cz, tel. +420412372632
1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:
1. lekce 1. Minimální program do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme: #include #include int main() { printf("hello world!\n"); return 0; 2.
dovolují dělení velkých úloh na menší = dekompozice
Podprogramy dovolují dělení velkých úloh na menší = dekompozice Příklad: Vytiskněte tabulku malé násobilky ve tvaru XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X X 1 2 3 4 5 6 7 8 9 10 X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Sada 1 - Základy programování
S třední škola stavební Jihlava Sada 1 - Základy programování 06. Proměnné, deklarace proměnných Digitální učební materiál projektu: SŠS Jihlava šablony registrační číslo projektu:cz.1.09/1.5.00/34.0284
Lineární datové struktury
Lineární datové struktury doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava Prezentace ke dni 13. března 2017 Jiří Dvorský (VŠB TUO) Lineární datové
Rekurzivní algoritmy
Rekurzivní algoritmy prof. Ing. Pavel Tvrdík CSc. Katedra počítačových systémů Fakulta informačních technologií České vysoké učení technické v Praze c Pavel Tvrdík, 2010 Efektivní algoritmy (BI-EFA) ZS
Vzorce. StatSoft. Vzorce. Kde všude se dá zadat vzorec
StatSoft Vzorce Jistě se Vám již stalo, že data, která máte přímo k dispozici, sama o sobě nestačí potřebujete je nějak upravit, vypočítat z nich nějaké další proměnné, provést nějaké transformace, Jinak
Abstraktní datové typy FRONTA
Abstraktní datové typy FRONTA Fronta je lineární datová struktura tzn., že ke každému prvku s výjimkou posledního náleží jeden následník a ke každému prvku s výjimkou prvního náleží jeden předchůdce. Do
14.4.2010. Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.
Základy programování (IZAPR) Přednáška 7 Ing. Michael Bažant, Ph.D. Katedra softwarových technologií Kancelář č. 229, Náměstí Čs. legií Michael.Bazant@upce.cz Obsah přednášky 7 Parametry metod, předávání
Úvod do programování - Java. Cvičení č.4
Úvod do programování - Java Cvičení č.4 1 Sekvence (posloupnost) Sekvence je tvořena posloupností jednoho nebo více příkazů, které se provádějí v pevně daném pořadí. Příkaz se začne provádět až po ukončení
Výčtový typ strana 67
Výčtový typ strana 67 8. Výčtový typ V této kapitole si ukážeme, jak implementovat v Javě statické seznamy konstant (hodnot). Příkladem mohou být dny v týdnu, měsíce v roce, planety obíhající kolem slunce
6. Příkazy a řídící struktury v Javě
6. Příkazy a řídící struktury v Javě Příkazy v Javě Příkazy v Javě Řídicí příkazy (větvení, cykly) Přiřazovací příkaz = Řízení toku programu (větvení, cykly) Volání metody Návrat z metody - příkaz return
PB161 Programování v jazyce C++ Přednáška 9
PB161 Programování v jazyce C++ Přednáška 9 Právo friend Přetěžování operátorů Nikola Beneš 16. listopadu 2015 PB161 přednáška 9: friend, přetěžování operátorů 16. listopadu 2015 1 / 30 Reklama PB173 Tematicky
1. Implementace funkce počet vrcholů. Předmět: Algoritmizace praktické aplikace (3ALGA)
Předmět: Algoritmizace praktické aplikace (3ALGA) Vytvořil: Jan Brzeska Zadání: Vytvoření funkcí na stromech (reprezentace stromu směrníky). Zadané funkce: 1. Počet vrcholů 2. Počet listů 3. Součet 4.
Mělká a hluboká kopie
Karel Müller, Josef Vogel (ČVUT FIT) Mělká a hluboká kopie BI-PA2, 2011, Přednáška 5 1/28 Mělká a hluboká kopie Ing. Josef Vogel, CSc Katedra softwarového inženýrství Katedra teoretické informatiky, Fakulta
Jazyk C++ II. STL knihovna kontejnery část 1
Jazyk C++ II STL knihovna kontejnery část 1 AR 2013/2014 Jazyk C++ II STL kontejnery Kontejnery jsou třídy, jejichž instance slouží k uskladňování dat. Každý druh kontejneru má své výhody a nevýhody. Kontejnery
Programovací jazyk. - norma PASCAL (1974) - implementace Turbo Pascal, Borland Pascal FreePascal Object Pascal (Delphi)
Programovací jazyk - norma PASCAL (1974) - implementace Turbo Pascal, Borland Pascal FreePascal Object Pascal (Delphi) Odlišnosti implementace od normy - odchylky např.: nepovinná hlavička programu odlišná
SII - Informatika. 1. Atribut relace, jehož hodnota jednoznačně určuje prvek v jiné relaci, se nazývá:
SII - Informatika Způsob vyhodnocení: Při vyhodnocení budou za nesprávné odpovědi strhnuty body. 1. Atribut relace, jehož hodnota jednoznačně určuje prvek v jiné relaci, se nazývá: a) sekundární klíč b)
ALGORITMIZACE A PROGRAMOVÁNÍ
Metodický list č. 1 Algoritmus a jeho implementace počítačovým programem Základním cílem tohoto tematického celku je vysvětlení pojmů algoritmus a programová implementace algoritmu. Dále je cílem seznámení
ABSTRAKTNÍ DATOVÉ TYPY
Jurdič Radim ABSTRAKTNÍ DATOVÉ TYPY Veškeré hodnoty, s nimiž v programech pracujeme, můžeme rozdělit do několika skupin zvaných datové typy. Každý datový typ představuje množinu hodnot, nad kterými můžeme
Kolekce, cyklus foreach
Kolekce, cyklus foreach Jen informativně Kolekce = seskupení prvků (objektů) Jednu již známe pole (Array) Kolekce v C# = třída, která implementuje IEnumerable (ICollection) Cyklus foreach ArrayList pro
Homer. prvky. délka. přední 0 zadní 4. Použití fronty BUS STOP. 3 Lisa. 2 Bart. 4 Maggie. 1 Marge. Grafické znázornění předchozí animace:
Fronta Fronta je sekvence first-in-first-out (první do fronty první z fronty) prvků. Prvky mohou být vkládány pouze nakonec (rear) fronty a odstraňovány pouze zpočátku (front) fronty Délka fronty je počet
Jazyk Scheme: jeho syntax a sémantika
Jazyk Scheme: jeho syntax a sémantika Vilém Vychodil, vilemvychodil@upolcz Syntaxe Scheme program v jazyku Scheme = konečná posloupnost symbolických výrazů symbolický výraz(s-výraz/ symbolic expression/
Datové typy a struktury
atové typy a struktury Jednoduché datové typy oolean = logická hodnota (true / false) K uložení stačí 1 bit často celé slovo (1 byte) haracter = znak Pro 8-bitový SII kód stačí 1 byte (256 možností) Pro
Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007
Úvod do programovacích jazyků (Java) Michal Krátký Katedra informatiky VŠB Technická univerzita Ostrava Úvod do programovacích jazyků (Java), 2006/2007 c 2006 Michal Krátký Úvod do programovacích jazyků
Binární soubory (datové, typované)
Binární soubory (datové, typované) - na rozdíl od textových souborů data uložena binárně (ve vnitřním tvaru jako v proměnných programu) není čitelné pro člověka - všechny záznamy téhož typu (může být i
Program a životní cyklus programu
Program a životní cyklus programu Program algoritmus zapsaný formálně, srozumitelně pro počítač program se skládá z elementárních kroků Elementární kroky mohou být: instrukce operačního kódu počítače příkazy
Test prvočíselnosti. Úkol: otestovat dané číslo N, zda je prvočíslem
Test prvočíselnosti Úkol: otestovat dané číslo N, zda je prvočíslem 1. zkusit všechny dělitele od 2 do N-1 časová složitost O(N) cca N testů 2. stačí zkoušet všechny dělitele od 2 do N/2 (větší dělitel
Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010
Dynamické programování Jiří Vyskočil, Marko Genyg-Berezovskyj 2010 Rozděl a panuj (divide-and-conquer) Rozděl (Divide): Rozděl problém na několik podproblémů tak, aby tyto podproblémy odpovídaly původnímu