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

Podobné dokumenty
Paradigmata programování II Přednáška 6: Líné vyhodnocování, proudy a kešované vyhodnocování

Paradigmata programování 1

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

Paradigmata programování 1

Paradigmata programování II Korutiny a nedeterminismus

PARADIGMATA PROGRAMOVÁNÍ 2 KORUTINY, NEDETERMINISMUS

Paradigmata programování 1

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

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

Paradigmata programování 2

PARADIGMATA PROGRAMOVÁNÍ 2A VEDLEJŠÍ EFEKT

1. Od Scheme k Lispu

PARADIGMATA PROGRAMOVÁNÍ 2A MAKRA III

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

PARADIGMATA PROGRAMOVÁNÍ 2A MUTACE

PARADIGMATA PROGRAMOVÁNÍ 2A MAKRA I

PARADIGMATA PROGRAMOVÁNÍ 2 AKTUÁLNÍ POKRAƒOVÁNÍ

Přednáška 3. Rekurze 1

Paradigmata programování 1

(pracovní verze textu určená pro studenty)

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

Stream API. Petr Krajča. Základy programovaní 4 (Java) Katedra informatiky Univerzita Palackého v Olomouci

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]

Funkcionální programování úvod

Základní datové struktury

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

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

Lokální definice (1) plocha-kruhu

9 - Map/filter/reduce OMO. Ing. David Kadleček, PhD

Jazyk Scheme: jeho syntax a sémantika

SII - Informatika. 1. Atribut relace, jehož hodnota jednoznačně určuje prvek v jiné relaci, se nazývá:

IB015 Neimperativní programování. Časová složitost, Typové třídy, Moduly. Jiří Barnat Libor Škarvada

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.

Programování v Pythonu

Programovací jazyk Haskell

Databázové systémy. * relační kalkuly. Tomáš Skopal. - relační model

ALGORITMIZACE PRAKTICKÉ

Programovací í jazyk Haskell

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

Definice uživatelského typu. Uživatelem definované typy. Součinové datové typy. Součtové datové typy. FLP - Uživatelem definované typy

Sdílení dat mezi podprogramy

Test prvočíselnosti. Úkol: otestovat dané číslo N, zda je prvočíslem

14. Složitější konstrukce

IB015 Neimperativní programování. Redukční strategie, Seznamy program QuickCheck. Jiří Barnat Libor Škarvada

Odvozené a strukturované typy dat

Programování v Pythonu

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

Struktura programu v době běhu

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

int ii char [16] double dd název adresa / proměnná N = nevyužito xxx xxx xxx N xxx xxx N xxx N

Dynamické datové struktury I.

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ě

Dynamicky vázané metody. Pozdní vazba, virtuální metody

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

IB015 Neimperativní programování. Seznamy, Typy a Rekurze. Jiří Barnat Libor Škarvada

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

Rekurzivní algoritmy

Programování 3. hodina. RNDr. Jan Lánský, Ph.D. Katedra informatiky a matematiky Fakulta ekonomických studií Vysoká škola finanční a správní 2015

Lineární datové struktury

LISP Definice funkcí

Algoritmizace a programování

Jazyk C# (seminář 6)

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

INVESTICE DO ROZVOJE VZDĚLÁVÁNÍ. Modernizace studijního programu Matematika na PřF Univerzity Palackého v Olomouci CZ.1.07/2.2.00/28.

Algoritmizace a programování

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

INVESTICE DO ROZVOJE VZDĚLÁVÁNÍ. Modernizace studijního programu Matematika na PřF Univerzity Palackého v Olomouci CZ.1.07/2.2.00/28.

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

Lambda funkce Novinky v interfaces Streamy Optional - aneb zbavujeme se null. Java 8. Ondřej Hrstka

Základní datové struktury III: Stromy, haldy

Denotační sémantika. Marek Běhálek

Abstraktní datové typy FRONTA

Objektové programování

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

1. Implementace funkce počet vrcholů. Předmět: Algoritmizace praktické aplikace (3ALGA)

Implementace aritmetického stromu pomocí směrníků

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Programování v Pythonu

Třídy a struktury v C++

Funkce pokročilé možnosti. Úvod do programování 2 Tomáš Kühr

Lineární spojový seznam (úvod do dynamických datových struktur)

6. blok část C Množinové operátory

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ě

Programování v Pythonu

8 Třídy, objekty, metody, předávání argumentů metod

Programování v jazyce JavaScript

Úvod do programovacích jazyků (Java)

Úvod do simulace - 1

Dolování asociačních pravidel

Programování v jazyce C pro chemiky (C2160) 3. Příkaz switch, příkaz cyklu for, operátory ++ a --, pole

Čtvrtek 3. listopadu. Makra v Excelu. Obecná definice makra: Spouštění makra: Druhy maker, způsoby tvorby a jejich ukládání

Informační systémy 2008/2009. Radim Farana. Obsah. Dotazy přes více tabulek

Operátory ROLLUP a CUBE

Úvod do informatiky. Miroslav Kolařík

PŘETĚŽOVÁNÍ OPERÁTORŮ

Programujeme v softwaru Statistica

Prolog PROgramming in LOGic část predikátové logiky prvního řádu rozvoj začíná po roce 1970 Robert Kowalski teoretické základy Alain Colmerauer, David

Jazyk C# (seminář 5)

Datové struktury. alg12 1

Transkript:

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 6 Přísliby, streamy 1 / 24

Přísliby a líné vyhodnocování Základní myšlenka místo vyhodnocení daného výrazu pracujeme s příslibem jeho budoucího vyhodnocení příslib = nový typ elementu (element prvního řádu) Co je potřeba k tomu, aby to fungovalo: 1 k dispozici je spec. forma (nejčastěji zvaná delay), která pro daný výraz vrací příslib jeho vyhodnocení 2 k dispozici je procedura (nejčastěji zvaná force), která pro daný příslib aktivuje výpočet a vrátí hodnotu vzniklou vyhodnocením přislíbeného výrazu Líné vyhodnocování: vyhodnocování založené na příslibech někdy se nazývá «call by need» (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 2 / 24

Příklad zamýšleného použití (delay (+ 1 2)) = #<promise> (define p (delay (map - (1 2 3 4)))) p = #<promise> (promise? p) = #t (force p) = (-1-2 -3-4) Poznámky: delay nemůže být z principu procedura, protože chceme, aby se přislíbený výraz vyhodnotil až při aktivaci pomocí force při líném vyhodnocování dochází k propagaci chyb (chyba se projeví na jiném místě než kde vznikla ) (define p (delay blah)) proběhne bez problémů p = #<promise>. (force p) = CHYBA: blah nemá vazbu (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 3 / 24

pomocí příslibů je možné odložit časově složitý výpočet na později a aktivovat jej, až je skutečně potřeba jej provést Modelový časově náročný výpočet: (define fib (lambda (n) (if (<= n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))) Příklad použití (define p (delay (fib 30))). (force p) proběhne okamžitě aktivace výpočtu (prodleva) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 4 / 24

Při použití příslibů vyvstávají otázky spojené s vedlejším efektem. Příslib výrazu, který má vedlejší efekt: (define p (let ((i 0)) (delay (begin (set! i (+ i 1)) i)))) Dvojí aktivace výpočtu: (force p) = 1 (force p) =??? Možnosti: 1 druhá aktivace (force p) vrací 1 2 druhá aktivace (force p) vrací 2, třetí vrací 3,... Ukážeme, jak implementovat líné vyhodnocování umožňující obě varianty. (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 5 / 24

Implementace příslibů a líného vyhodnocování přísliby lze plně implementovat pomocí procedur vyšších řádů, maker a vedlejších efektů Základní myšlenka: při vytváření procedur (vyhodnocováním λ-výrazů) nedochází k vyhodnocování těla nově vznikajících procedur k vyhodnocování těla procedur dochází až při jejich aplikaci nabízí se tedy: vytvořit přísliby pomocí procedur Vysvětlující příklad (lambda () (+ 1 2)) (define p (lambda () (+ 1 2))) (p) #<procedure> náš příslib aktivace (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 6 / 24

Implementace příslibů a líného vyhodnocování jednodušší verze při každé aktivaci příslibu je přislíbený výraz vždy vyhodnocen vytvoříme makro freeze ( zmraz ) a proceduru thaw ( roztaj ) ;; speciální forma freeze (define-macro freeze (lambda exprs (lambda () (begin,@exprs)))) ;; procedura thaw (define thaw (lambda (promise) (promise))) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 7 / 24

Příklad vytvoření příslibu (define p (let ((x 10)) (freeze (display "Hodnota: ") (display x) (newline) (set! x (+ x 1)) (list x (* x x))))) Příklad aktivace příslibu (thaw p) = (11 121) (thaw p) = (12 144) (thaw p) = (13 169) Příslib jako součást složitějšího výrazu (reverse (thaw p)) = (225 14) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 8 / 24

Implementace příslibů a líného vyhodnocování složitější verze při první aktivaci příslibu je výsledek vyhodnocení přislíbeného výraz zapamatován (uvnitř příslibu) a při každé další aktivaci příslibu je vrácena zapamatovaná hodnota případné vedlejší efekty se projeví jen při první aktivaci vytvoříme makro delay a proceduru force Nejprve příklad použití: (define p (let ((x 10)) (delay (set! x (+ x 1)) (list x (* x x))))) (force p) = (11 121) (force p) = (11 121) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 9 / 24

Implementace příslibů a líného vyhodnocování Speciální forma delay (define-macro delay (lambda exprs (let ((result (lambda () (begin,@exprs))) (evaluated? #f)) (lambda () (begin (if (not evaluated?) (begin (set! evaluated? #t) (set! result (result)))) result))))) ;; procedura force (totéž co thaw) (define force thaw) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 10 / 24

Proudy (angl. Streams) proudy jsou nejčastěji používanou aplikací líného vyhodnocování neformálně: proudy jsou líně vyhodnocované seznamy konstruktor cons-stream a selektory stream-car a stream-cdr ;; Konstruktor proudu cons-stream je makro (define-macro cons-stream (lambda (a b) (cons,a (delay,b)))) ;; selektor stream-car (vrať první prvek proudu) (define stream-car car) ;; selektor stream-cdr (vrať proud bez prvního prvku) (define stream-cdr (lambda (stream) (force (cdr stream)))) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 11 / 24

Definice proudů prázdný seznam je proud; každý tečkový pár (e. p), kde e je libovolný element a p je příslib proudu, je proud. ;; je stream prázdný? (define stream-null? null?) ;; predikát stream? (podle definice) (define stream? (lambda (elem) (or (null? elem) (and (pair? elem) (and (promise? (cdr elem)) (stream? (force (cdr elem)))))))) předchozí predikát stream? má nevýhodu: používá force (!) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 12 / 24

;; slabší verze predikátu stream? ;; každý pár, jehož 2. prvek je příslib nebo () je stream (define stream? (lambda (elem) (or (null? elem) (and (pair? elem) (or (promise? (cdr elem)) (null? (cdr elem))))))) Pomocné procedury: ;; zobraz stream, nanejvýš však n prvních prvků (define display-stream (lambda (stream. n) ;; odvozené selektory (define stream-caar (lambda (x). (define stream-cddddr (lambda (x) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 13 / 24

Procedury pro práci s proudy ;; délka proudu (define stream-length (lambda (stream) (if (stream-null? stream) 0 (+ 1 (stream-length (stream-cdr stream)))))) ;; mapování přes proudy (mapování přes jeden stream) (define stream-map2 (lambda (f stream) (if (stream-null? stream) () (cons-stream (f (stream-car stream)) (stream-map f (stream-cdr stream)))))) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 14 / 24

Procedury pro práci s proudy ;; mapování přes proudy (obecná verze) (define stream-map (lambda (f. streams) (if (stream-null? (car streams)) () (cons-stream (apply f (map stream-car streams)) (apply stream-map f (map stream-cdr streams)))))) ;; konvertuj seznam na stream (define list->stream (lambda (list) (foldr (lambda (x y) (cons-stream x y)) () list))) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 15 / 24

Procedury pro práci s proudy ;; vytvoř konečný stream daných prvků (define stream (lambda args (list->stream args))) Příklady použití předchozích procedur: (define s (stream 1 2 3 4)) s = (1. #<promise>) (display-stream s) = #<stream (1 2 3 4)> (display-stream s 2) = #<stream (1 2)> (stream-length s) = 4 (display-stream (stream-map - s) 2) = #<stream (-1-2)> (display-stream (stream-map + s s s)) = #<stream (3 6 9 12)> (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 16 / 24

Všimněte si při práci s proudy mají jednotlivé procedury jinou odezvu výpočet je řízen daty, dochází k propagaci chyb Výsledek je vrácen okamžitě (define fs (stream-map fib (stream 1 30 31 50))) fs = (1. #<promise>) přístup ke dalším prvkům se bude postupně zpomalovat ukázka propagace chyb v proudech: (define s (stream 1 2 3 4 5 blah 6 7)) (define r (stream-map - s)) r = (-1. #<promise>) (display-stream r 4) = (-1-2 -3-4) (display-stream r 6) = (-1-2 -3-4 -5 CHYBA (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 17 / 24

Úskalí ;; zdánlivě funkční verze foldr pro proudy (define stream-foldr (lambda (f nil. streams) (if (stream-null? (car streams)) nil (apply f (,@(map stream-car streams),(apply stream-foldr f nil (map stream-cdr streams))))))) ;; následující se nechová přirozeně (stream-foldr (lambda (x y) (cons-stream (- x) y)) () (stream 1 2 3 blah 4)) = CHYBA: nelze aplikovat - na symbol blah Čekali bychom, že chyba se projeví až při pokusu přistoupit ke 4. prvku výsledného proudu (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 18 / 24

Nová verze stream-foldr proceduře f bude předáván místo druhého argumentu jeho příslib procedura sama rozhodne, jak bude s příslibem nakládat ;; procedura stream-folder (define stream-foldr (lambda (f nil. streams) (if (stream-null? (car streams)) nil (apply f (,@(map stream-car streams),(delay (apply stream-foldr f nil (map stream-cdr streams)))))))) (stream-foldr (lambda (x y) (cons-stream (- x) (force y))) () (stream 1 2 3 blah 4)) = (-1. #<promise>) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 19 / 24

Další (užitečné) odvozené procedury ;; konverze proudu na seznam (define stream->list (lambda (stream) (stream-foldr (lambda (x y) (cons x (force y))) () stream))) ;; filtrace prvku proudu podle vlastnosti (define stream-filter (lambda (prop? stream) (stream-foldr (lambda (x y) (if (prop? x) (cons-stream x (force y)) (force y))) () stream))) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 20 / 24

Nekonečné proudy a jejich implicitní definice Příklad (proud jedniček) ;; rekurzivní procedura bez limitní podmínky (define ones-proc (lambda () (cons-stream 1 (ones-proc)))) ;; nekonečný proud vytvořený voláním ones-proc (define ones (ones-proc)) ;; předchozí s použitím pojmenovaného let (define ones (let proc () (cons-stream 1 (proc)))) ;; implicitní definice proudu (define ones (cons-stream 1 ones)) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 21 / 24

Nekonečné proudy a jejich implicitní definice Příklad (proud přirozených čísel) ;; rekurzivní procedura bez limitní podmínky (define naturals-proc (lambda (i) (cons-stream i (naturals-proc (+ i 1))))) ;; nekonečný proud vytvořený voláním naturals-proc (define naturals (naturals-proc 1)) ;; předchozí s použitím pojmenovaného let (define naturals (let iter ((i 1)) (cons-stream i (iter (+ i 1))))) ;; implicitní definice proudu (define naturals (cons-stream 1 (stream-map + ones naturals))) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 22 / 24

Nekonečné proudy Nekonečný proud neformálně: potenciálně nekonečná lineární datová struktura potenciálně nekonečná znamená: opakovaným použitím stream-cdr se nedostaneme na jejich konec v každém okamžiku průchodu nekonečným proudem máme vždy k dispozici aktuální prvek a příslib pokračování proudu lze se na něj dívat jako na nekonečnou posloupnost elementů (e i ) i=0, to jest e 0, e 1, e 2,..., e n 1, e n, e n+1,... v praxi se konstruuje rekurzivní procedurou bez limitní podmínky ;; proud hodnot (2 i ) i=0 (define pow2 (let next ((last 1)) (cons-stream last (next (* 2 last))))) (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 23 / 24

Nekonečné proudy Formálně lze zavést jako limity prefixových generátorů Seznam r je prefix seznamu t, pokud lze t vyjádřit jako spojení r s nějakým seznamem l (v tomto pořadí). Množinu seznamů S nazveme prefixový generátor, pokud 1 pro každé n N, systém S obsahuje seznam délky n; 2 pro každé dva s, t S platí: buď s je prefix t, nebo t je prefix s. Nekonečný proud (příslušný prefixovému generátoru S) je element reprezentující posloupnost (e i ) i=0, kde e i je element nacházející se na i-té pozici libovolného seznamu s S majícího alespoň i + 1 prvků. (KI, UP Olomouc) PP 2, Lekce 6 Přísliby, streamy 24 / 24