Ján Kollár Funkcionálne programovanie 1

Σχετικά έγγραφα
Ekvačná a kvantifikačná logika

Matematika Funkcia viac premenných, Parciálne derivácie

1. Limita, spojitost a diferenciálny počet funkcie jednej premennej

Cvičenie č. 4,5 Limita funkcie

Matematika prednáška 4 Postupnosti a rady 4.5 Funkcionálne rady - mocninové rady - Taylorov rad, MacLaurinov rad

Goniometrické rovnice a nerovnice. Základné goniometrické rovnice

Start. Vstup r. O = 2*π*r S = π*r*r. Vystup O, S. Stop. Start. Vstup P, C V = P*C*1,19. Vystup V. Stop

Tomáš Madaras Prvočísla

7. FUNKCIE POJEM FUNKCIE

ΠΑΝΕΠΙΣΤΗΜΙΟ ΠΑΤΡΩΝ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΜΑΘΗΜΑΤΙΚΩΝ ΙΠΛΩΜΑΤΙΚΗ ΕΡΓΑΣΙΑ

6 Limita funkcie. 6.1 Myšlienka limity, interval bez bodu

Τι σημαίνουν οι τύποι συναρτήσεων στην ML. Παράδειγμα επισημειώσεων τύπων στην ML. Επισημειώσεις τύπων (type annotations) f : A B σημαίνει:

Kompilátory. Cvičenie 6: LLVM. Peter Kostolányi. 21. novembra 2017

Πολυμορφισμός και Υπερφόρτωση

Obvod a obsah štvoruholníka

Η γλώσσα ML σε βάθος. Τι σημαίνουν οι τύποι συναρτήσεων στην ML. Παράδειγμα επισημειώσεων τύπων στην ML. Επισημειώσεις τύπων (type annotations)

Haskell: Βασικές Δομές Δεδομένων και Απόκρυψη Ονομάτων

Η γλώσσα ML σε βάθος. Joan Miró, El Carnaval del Arlequín, Κωστής Σαγώνας Νίκος Παπασπύρου

Τι σηµαίνουν οι τύποι συναρτήσεων στην ML. Παράδειγµα επισηµειώσεων τύπων στην ML. Επισηµειώσεις τύπων (type annotations) Σύνταξη ταιριάσµατος

Συναρτησιακός Προγραμματισμός 2008 Λύσεις στο Δεύτερο Φύλλο Ασκήσεων

Η γλώσσα ML σε βάθος. Γλώσσες Προγραμματισμού Ι. Διδάσκοντες: Νικόλαος Παπασπύρου, Κωστής Σαγώνας

Motivácia Denícia determinantu Výpo et determinantov Determinant sú inu matíc Vyuºitie determinantov. Determinanty. 14. decembra 2010.

ΚΥΡΙΑ ΜΟΝΤΕΛΑ ΓΛΩΣΣΩΝ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ

Prechod z 2D do 3D. Martin Florek 3. marca 2009

Moderné vzdelávanie pre vedomostnú spoločnosť Projekt je spolufinancovaný zo zdrojov EÚ M A T E M A T I K A

ARMA modely čast 2: moving average modely (MA)

Gramatická indukcia a jej využitie

Κεφάλαιο 8. Συναρτησιακός Προγραμματισμός: Η Γλώσσα Haskell. Προπτυχιακό μάθημα Αρχές Γλωσσών Προγραμματισμού Π. Ροντογιάννης

Komplexné čísla, Diskrétna Fourierova transformácia 1

Εισαγωγή στη γλώσσα Haskell

Planárne a rovinné grafy

Integrovanie racionálnych funkcií

M6: Model Hydraulický systém dvoch zásobníkov kvapaliny s interakciou

Úvod do lineárnej algebry. Monika Molnárová Prednášky

4. Výrokové funkcie (formy), ich definičný obor a obor pravdivosti

PREHĽAD ZÁKLADNÝCH VZORCOV A VZŤAHOV ZO STREDOŠKOLSKEJ MATEMATIKY. Pomôcka pre prípravný kurz

Návrh vzduchotesnosti pre detaily napojení

Matematika 2. časť: Funkcia viac premenných Letný semester 2013/2014

Spojité rozdelenia pravdepodobnosti. Pomôcka k predmetu PaŠ. RNDr. Aleš Kozubík, PhD. 26. marca Domovská stránka. Titulná strana.

Reálna funkcia reálnej premennej

Jednotkový koreň (unit root), diferencovanie časového radu, unit root testy

Matematika 2. časť: Analytická geometria

Odporníky. 1. Príklad1. TESLA TR

x x x2 n

Riešenie cvičení z 5. kapitoly

Εισαγωγή στη Γλώσσα ML. Juan Miró

Goniometrické substitúcie

Κεφάλαιο 10 H γλώσσα συναρτησιακού προγραμματισμού Haskell Τα βασικά

Εισαγωγή στη Γλώσσα ML

Δομές Δεδομένων & Αλγόριθμοι

Základné vzťahy medzi hodnotami goniometrických funkcií

Funkcie - základné pojmy

Lineárna algebra I - pole skalárov, lineárny priestor, lineárna závislosť, dimenzia, podpriestor, suma podpriestorov, izomorfizmus

Στοίβες - Ουρές. Στοίβα (stack) Γιάννης Θεοδωρίδης, Νίκος Πελέκης, Άγγελος Πικράκης Τµήµα Πληροφορικής

ARMA modely čast 2: moving average modely (MA)

Definícia parciálna derivácia funkcie podľa premennej x. Definícia parciálna derivácia funkcie podľa premennej y. Ak existuje limita.

2. prednáška. Teória množín I. množina operácie nad množinami množinová algebra mohutnosť a enumerácia karteziánsky súčin

Dynamic types, Lambda calculus machines Section and Practice Problems Apr 21 22, 2016

VLASTNÉ ČÍSLA A JORDANOV KANONICKÝ TVAR. Michal Zajac. 3 T b 1 = T b 2 = = = 2b

Ορισμός Συναρτήσεων στην ΜL

Motivácia pojmu derivácia

MIDTERM (A) riešenia a bodovanie

FUNKTSIONAALNE PROGRAMMEERIMINE. Skeemid. Eesmärk: esitada riistvara skeeme ja teisi andmevoodiagrammidel baseeruvaid kirjeldusi Haskellis

Κεφάλαιο 11 Εκφραστικές δυνατότητες της Haskell

Μοντέλα Προγραµµατισµού

AerobTec Altis Micro

FUNKCIE N REÁLNYCH PREMENNÝCH

Vybrané partie z logiky

Automaty a formálne jazyky

Lambda calculus. Štruktúra prednášok: úvod do syntaxe, netypovaný λ-kalkul (gramatika + konvencie) sémantika (redukčné pravidlá)

n true false if t then t else t u t t b t emptylist cons t t t t λx.t u ::= head tail isempty

Metódy vol nej optimalizácie

3. prednáška. Komplexné čísla

MATEMATICKÁ ANALÝZA 1

Vektorový priestor V : Množina prvkov (vektory), na ktorej je definované ich sčítanie a ich

Ευφυής Προγραμματισμός

3. Striedavé prúdy. Sínusoida

,Zohrievanie vody indukčným varičom bez pokrievky,

Obsah. 1.1 Reálne čísla a ich základné vlastnosti Komplexné čísla... 8

Symbolická logika. Stanislav Krajči. Prírodovedecká fakulta

Goniometrické rovnice riešené substitúciou

HASLIM112V, HASLIM123V, HASLIM136V HASLIM112Z, HASLIM123Z, HASLIM136Z HASLIM112S, HASLIM123S, HASLIM136S

9. kapitola Boolove funkcie a logické obvody

Σύντομη Εισαγωγή στην SML/NJ

Teória funkcionálneho a logického programovania

MATEMATICKÁ OLYMPIÁDA

RIEŠENIE WHEATSONOVHO MOSTÍKA

REZISTORY. Rezistory (súčiastky) sú pasívne prvky. Používajú sa vo všetkých elektrických

Δομές Δεδομένων (Data Structures)

Technická univerzita v Košiciach Fakulta elektrotechniky a informatiky MATEMATIKA II. Zbierka riešených a neriešených úloh

Číslo a číslica. Pojem čísla je jedným zo základných pojmov matematiky. Číslo je abstraktná entita (fil. niečo existujúce) používaná na opis množstva.

Εισαγωγή στη Γλώσσα ML

Numerická lineárna algebra. Zobrazenie

7 Derivácia funkcie. 7.1 Motivácia k derivácii

Základy matematickej štatistiky

Harmonizované technické špecifikácie Trieda GP - CS lv EN Pevnosť v tlaku 6 N/mm² EN Prídržnosť

The Simply Typed Lambda Calculus

p(α 1 ) = u 1. p(α n ) = u n. Definícia (modulárna reprezentácia polynómu). Zobrazenie

KATEDRA DOPRAVNEJ A MANIPULAČNEJ TECHNIKY Strojnícka fakulta, Žilinská Univerzita

Automatizácia technologických procesov

Transcript:

Ján Kollár Funkcionálne programovanie 1 Jazyky procedurálne, objektové, deklaratívne (aplikatívne, popisné) logické, funkcionálne. Čisté funkcionálne jazyky (bez procedurálnych prvkov) Orwell, Gofer, Hugs98, Haskell, Miranda. Teoretický základ Moses Schönfinkel, Haskell Curry kombinatorická logika, Alonzo Church jazyk lambda (lambda kalkul) základný, rozšírený Implementácia pomocou rozšíreného jazyka lambda (výrazy if, case, let, letrec) (Simon Peyton Jones, Philip Wadler, David Turner) Procedurálna metodológia programovania popis problému, organizácia pamäti, organizácia postupnosti krokov. Metodológia funkcionálneho programovania iba popis (formálny opis) problému. žiadne procedurálne prvky (premenné ako bunky, priradenie, postupnosť krokov), matematický pojem premennej, funkcie vyššieho rádu. Funkcionálny program je výraz konštantná aplikatívna forma (CAF), množina rekurzívnych funkcií a hlavná funkcia vždy konštanta. Rozšírená štruktúra funkcionálneho programu modularita, import, export, riešenie kolízie mien, typové triedy a ich inštancie, obsahujúce definície prekrývaných operácií (funkcií) Typový polymorfizmus parametrický aj prekrývanie (overloading), statická kontrola typov. Vykonávanie funkcionálneho programu postupná aplikácia funkcií na argumenty(currying), transformácia CAF zjednodušenie redukcia (beta) výrazu lambda výpočet, implicitná konštrukcia údajových štruktúr, automatické uvoľňovanie z pamäti (garbage collection) Vedľajší účinok (side effect) dosiahnuteľný monadickými operáciami. Praktický prístup k funkcionálnemu programovaniu návrh zhora-nadol, implementácia (definícia funkcií) zdola-nahor, overovanie typov funkcií, aplikácia na vzorky argumentov, hľadanie čo nastručnejšej formy, využívajúc zameniteľnosť (konvertibilitu) výrazov, funkcie vyššieho rádu, nerekurzívne definície a množinové abstrakcie. Podrobné komentovanie neformálneho významu argumentov a hodnoty funkcie a uvádzanie testovacích aplikácií a ich hodnôt v dokumentácii. Koncepcia funkcionálneho programovania

Ján Kollár Funkcionálne programovanie 2 data T α 1 α 2... α u = C 0 T 0,1 T 0,2... T 0,n0 C 1 T 1,1 T 1,2... T 1,n1 C 2 T 2,1 T 2,2... T 2,n2....... C m T m,1 T m,2... T m,nm f :: T 1 T 2... T n T f p 1,1 p 1,2... p 1,n = e 1 f x 1 x 2... x n = e f p 2,1 p 2,2... p 2,n = e 2 f p q,1 p q,2... p q,n = e q f m 1 m 2... m n T 1 T 2... T n T T 1 (T 2 (... (T n T ))...)) f m 1 m 2... m n (... ((f m 1 ) m 2 )... ) m n Základné prvky funkcionálneho jazyka

Ján Kollár Funkcionálne programovanie 3 add :: Int -> Int -> Int add x y = x + y add2 :: (Int,Int) -> Int add2 (x,y) = x + y add3 x y = x - y globálna úroveň definícií funkcií, význam funkcie, premenné (parametre) funkcie, vzory, arita funkcie - konštanta, unárna a binárna funkcia, funkcia n argumentov, mená funkcií, definícia (odvodenie) typu funkcie, operácie a typové operácie, definícia nového (algebraickeho) typu, typ sumárny, násobný, nerekurzívny a rekurzívny, typ konštruktora, význam konštruktora, princíp postupnej aplikácie funkcie, asociatívnosť operácie aplikácie, asociatívnosť typovej operácie zobrazenia, aplikácia konštruktora ako kanonickej funkcie, asociatívnosť typovej operácie zobrazenia, princíp výpočtu ako postupného zjednodušenia CAF (redukcie výrazu lambda) do kanonickej formy, zameniteľnosť výrazov, referenčná transparentnosť, hodnota (aplikácie) funkcie, funkcia ako hodnota, funkcie vyššieho rádu. Základné pojmy

Ján Kollár Funkcionálne programovanie 4 add x y = x + y square x = x * x main = add 2 (square 3) add 2 (square 3) add 2 (3 3) add 2 9 2 + 9 11 add 2 (square 3) 2 + (square 3) 2 + (3 3) 2 + 9 11 Výpočet na základe hodnoty a požiadavky (eager and lazy)

Ján Kollár Funkcionálne programovanie 5 module Main where import Data.Char add x y = x + y square x = x * x main = add 2 (square 3) -- main :: IO () -- pre GHC main = let add = \x->(\y->x+y) square = \x->x*x in (add 2 (square 3)) main = let add = \x->(\y->x+y); square = \x->x*x in (add 2 (square 3)) let x=2 in x*x = (\x->x*x) 2 let x=2; y=3 in x*y = LETREC x=2; y=3 in x*y Ekvivalentné formy: program a LETREC, definícia funkcie pomocou abstrakcie lambda, významy let (Haskell)

Ján Kollár Funkcionálne programovanie 6 f (x,y,z) = (f x, g y, h z) where f = (2*) g = (3*) h = (4*) f = \(x,y,z) -> let f = \x -> (2*) x g = \x -> (3*) x h = \x -> (4*) x in (f x, g y, h z) Ekvivalentné formy: where a LETREC

Ján Kollár Funkcionálne programovanie 7 fac 0 = 1 fac (n+1) = (n+1) * fac n fac n n == 0 = 1 n > 0 = n * fac (n-1) fac n = if (n == 0) then 1 else (if (n > 0) then (n * fac (n-1)) else undefined) Ekviv. formy: Porovnávanie vzorov pre celé nezáporné čísla (Hugs98), podmienené výrazy, if, otherwise, rekurzívna definícia fac n n == 0 = 1 fac 0 = 1 otherwise = n * fac (n-1) fac n = n * fac (n-1) fac n = n * fac (n-1) fac 0 = 1 Nesprávne definície: úplná namiesto neúplnej a nejednoznačná

Ján Kollár Funkcionálne programovanie 8 map f [] = [] map f (x:xs) = f x : map f xs map = \f ->(\p->case p of [] -> [] (x:xs) -> f x : map f xs) map = \f ->(\p->case p of [] -> [] (x:xs) -> ((\u->(\us->f u : map f us))) x xs) Ekvivalentné formy: porovnávanie vzorov pre zoznamy, case, kolízia mien (map)

Ján Kollár Funkcionálne programovanie 9 module Sorting (isort) where {- Triedenie vkladanim (insertsort) ----------------------------------------- isort :: [a] -> [a] isort xs... usporiadava zoznam prvkov xs, hodnotou je usporiadany zoznam prvkov foldr :: (a -> b -> b) -> b -> [a] -> b foldr op a [x1,x2,...,xn] = x1 op (x2 op (... op (xn op a)...)) kde op=insert, a=[] insert :: a -> [a] -> [a] insert x xs... vklada prvok x do prazdneho alebo usporiadaneho zoznamu xs tak, aby hodnotou bol usporiadany zoznam ---------------------------------------------------------------------------- -} -- isort :: [a] -> [a] isort xs = foldr insert [] xs where insert x [] = [x] insert x (y:ys) x<=y = x:y:ys otherwise = y:insert x ys -- Test: stringsort = isort "bsgat" numssort = isort [4,3,8,1,9,6,7] -- Aplikacia: > stringsort "abgst" > numssort [1,3,4,6,7,8,9] Príklad: Modul Sorting (sorting.hs), export isort

Ján Kollár Funkcionálne programovanie 10 isort :: Ord a => [a]->[a] isort = \xs -> let insert = \x->(\u-> (case u of [] -> [x] (y:ys)-> (\y->(\ys->(if (x<=y) then (x:y:ys) else (y:insert x ys)))) y ys)) in (foldr ins [] xs) Reprezentácia isort v rozšírenom jazyku lambda module Main where import qualified Sorting as S {- main ----------------------------------------- vypis usporiadanych zoznamov ---------------------------------------------- -} main = (putstr.show) (S.iSort [9,6,5,3,5,1,3]) >> (putstr.show) (S.iSort "abeceda") Príklad: Modul Main (main.hs), kvalifikácia importovanej funkcie isort, kompozícia a monadické operácie

Ján Kollár Funkcionálne programovanie 11 -- return :: a -> IO a -- (>>=):: IO a -> (a -> IO b) -> IO b -- (>>) :: IO a -> IO b -> IO b -- 1.verzia -- readnames :: [String] -> IO [String] readnames xs = getline >>= \s -> if s=="" then (return xs) else readnames (xs++[s]) -- 2.verzia readnames xs = getline >>= addname where addname s s=="" = return xs otherwise = readnames (xs++[s]) -- 3.verzia readnames xs = getline >>= addname xs addname xs s s=="" = return xs otherwise = readnames (xs++[s]) ------------------------------------------------------------------- main = readnames [] {- test *Main> main alfa beta gamma ["alfa","beta","gamma"] -- test zapisu do súboru: readnames [] >>= \xs -> writefile "testfile.txt" (concat xs) Aplikácia monadických operácií

Ján Kollár Funkcionálne programovanie 12 Asociatívnosť Operácia Význam doprava ^, ^^, ** mocnina doľava *, /, div, mod aritmetické operácie doľava +, - aritmetické operácie doprava ++ zreťazenie žiadna ==, /=, <, <=, >=, > porovnanie doprava && logický súčet doprava logický súčin Tabuľka 1: Vybrané binárne operácie Binárne operácie

Ján Kollár Funkcionálne programovanie 13 C i :: T 1,i T 1,i... T 1,ni T α 1 α 2... α u, i = 0... m m = 0 násobný typ T m > 0 sumárny typ T u = 0 monomorfný typ T u > 0 polymorfný typ T T i,j ; T T i,j T je nerekurzívny typ. T i,j ; T T i,j T je rekurzívny typ. Jednoduché typy Char, Int, Float Typ logických hodnôt. nerekurzívny typ. data Bool = F alse T rue Entice. nerekurzívny typ. data T uple2 a b = T uple2 a b data T uple3 a b c = T uple3 a b c data T uple4 a b c d = T uple4 a b c d Zoznamy. Zoznam (a String) je rekurzívny typ. data List a = Nil Cons a (List a) Celé nezáporné čísla. Rekurzívny typ. data N at = Zero Succ N at Klasifikácia typov a základné typy

Ján Kollár Funkcionálne programovanie 14 Pre entice Typ T uple2 a b (a, b), T uple3 a b c (a, b, c),... Konštruktor T uple2 e 1 e 2 (e 1, e 2 ), T uple3 e 1 e 2 e 3 (e 1, e 2, e 3 ),... Pre zoznamy Typ List a [a] Konštruktory Nil [], Cons e 1 e 2 (e 1 : e 2 ),... Syntaktická podpora zápisu entíc a zoznamov

Ján Kollár Funkcionálne programovanie 15 Enumeračný typ Variantný typ Binárny strom data F arba = F ialova Modra Zelena Zlta Cervena data ZnakAleboCislo = Z Char C Int data Btree a = T ip a Bin (Btree a) (Btree a) Binárny značkovaný strom data Lbtree a b = T ip a Bin b (Lbtree a b) (Lbtree a b) Binárny vyhľadávací strom data Bstree a = T ip Bin a (Bstree a) (Bstree a) Všeobecný strom data Gtree a = Node a [Gtree a] type String = [Char] type Matrix a = [[a]] type Graph a = [(a, [a])] Niektoré užitočné typy a synonymá typov

Ján Kollár Funkcionálne programovanie 16 class Show a where... typové signatúry... data Farba = Biela Modra instance Show Farba where show Biela = "Biela" show Modra = "Modra" data Farba = Biela Modra deriving (Eq,Show) Definícia resp. odvodenie operácií abstraktného typu pre nový algebraický typ

Ján Kollár Funkcionálne programovanie 17 fst (x,y) = x snd (x,y) = y reverse [] = [] reverse (x:xs) = reverse xs ++ [x] reversebtree (Tip x) = Tip x reversebtree (Bin tl tr) = Bin (reversebtree tr) (reversebtree tl) last [x] = x last (x:x :xs) = last (x :xs) length :: [a] -> Int length [] = 0 length (x:xs) = 1 + length xs (++) :: [a] -> [a] -> [a] [] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys concat :: [[a]] -> [a] concat [] = [] concat (xs:xss) = xs ++ concat xss Najdôležitejšie funkcie

Ján Kollár Funkcionálne programovanie 18 (!!) :: [a] -> Int -> a (x:xs)!! 0 = x (x:xs)!! (n+1) = xs!! n head :: [a] -> a head (x:xs) = x tail :: [a] -> [a] tail (x:xs) = xs init :: [a] -> [a] init [x] = [] init (x:y:xs) = x : init (y:xs) last :: [a] -> a last [x] = x last (x:y:xs) = last (y:xs) take :: Int -> [a] -> [a] take 0 xs = [] take (n+1) [] = [] take (n+1) (x:xs) = x : take n xs drop :: Int -> [a] -> [a] drop 0 xs = xs drop (n+1) [] = [] drop (n+1) (x:xs) = drop n xs Najdôležitejšie funkcie

Ján Kollár Funkcionálne programovanie 19 copy :: Int -> a -> [a] copy n x = take n xs where xs = x:xs space :: Int -> String space n = copy n map :: (a -> b) -> [a] ->[b] map f [] = [] map f (x:xs) = f x : map f xs filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x:xs) p x = x : filter p xs otherwise = filter p xs even :: Int -> Bool even x = (x mod 2) == 0 takewhile :: (a -> Bool) -> [a] -> [a] takewhile p [] = [] takewhile p (x:xs) p x = x : takewhile p xs otherwise = [] dropwhile :: (a -> bool) -> [a] -> [a] dropwhile p [] = [] dropwhile p (x:xs) p x = dropwhile p xs otherwise = x:xs Najdôležitejšie funkcie

Ján Kollár Funkcionálne programovanie 20 foldl :: (a -> b -> a) -> a -> [b] -> a foldl f a [] = a foldl f a (x:xs) = foldl f (f a x) xs foldr :: (a -> b -> b) -> b -> [a] -> b foldr f a [] = a foldr f a (x:xs) = f x (foldr f a xs) sum :: Num a => [a] -> a sum = foldl (+) 0 product :: Num a => [a] -> a product = foldl (*) 1 concat :: [[a]] -> [a] concat = foldr (++) [] and :: [Bool] -> Bool and = foldr (&&) True or :: [Bool] -> Bool or = foldr ( ) False foldl1 :: (a -> a -> a) -> [a] -> a foldl1 f (x:xs) = foldl f x xs foldr1 :: (a -> a -> a) -> [a] -> a foldr1 f [x] = x foldr1 f (x:y:xs) = f x (foldr1 f (y:xs)) Najdôležitejšie funkcie

Ján Kollár Funkcionálne programovanie 21 minimum :: [a] -> a minimum = foldl1 min maximum :: [a] -> a maximum = foldl1 max scan :: (a -> b -> a) -> a -> [b] -> [a] scan f a xs = a : sc f a xs where sc f a [] = [] sc f a (x:xs) = scan f (f a x) xs zip :: [a] -> [b] -> [(a, b)] zip [] ys = [] zip (x:xs) [] = [] zip (x:xs) (y:ys) = (x,y) : zip xs ys zipwith :: (a -> b -> c) -> [a] -> [b] -> [c] zipwith f [] [] = [] zipwith f [] (y:ys) = [] zipwith f (x:xs) [] = [] zipwith f (x:xs) (y:ys) = (f x y) : zipwith f xs ys Najdôležitejšie funkcie

Ján Kollár Funkcionálne programovanie 22 (A) Pravidlo aplikácie: (R) Pravidlo rovnosti: f x : T x : T f : T T x : T x : T T = T kde T je nový typ. (F) Pravidlo funkcie: T U = T U T T 1... T n = T T 1... T n T = T U = U T 1 = T 1... T n = T n (.) :: (b -> c) -> (a -> b) -> a -> c (f. g) x = f (g x) ( ) f g x = f (g x) ( ) : T 1 T 2 T 3 T 4 f : T 1 g : T 2 x : T 3 f (g x) : T 4 1. Poďľa (A): f (g x) : T 4 (g x) : T 5 f : T 5 T 4. 2. Poďľa (R): f : T 1 f : T 5 T 4 T 1 = T 5 T 4. 3. Poďľa (A): (g x) : T 5 x : T 6 g : T 6 T 5. 4. Poďľa (R): g : T 2 g : T 6 T 5 T 2 = T 6 T 5. 5. Poďľa (R): x : T 3 x : T 6 T 3 = T 6 = T 7. ( ) : (T 5 T 4 ) (T 7 T 5 ) T 7 T 4 (.) :: (b -> a) -> (c -> b) -> c -> a Pravidlá typovej kontroly a odvodenie typu kompozície

Ján Kollár Funkcionálne programovanie 23 f x = x x T 1 = T 1 T 2. f x y = fst x + fst y fst :: (a,b) -> a fst (x,y) = x f x y = fst 1 x + fst 2 y (+) : Int Int Int f : T 1 T 2 T 3 fst 1 : (T 4, T 5 ) T 4 fst 2 : (T 6, T 7 ) T 6 x : T 1 y : T 2 ((+) (fst 1 x))(fst 2 y) : T 3.................................... f :: (Int, a) (Int, b) Int (+)::Num a => a -> a -> a f :: Num a => (a,b) -> (a,c) -> a Odvodenie polymorfného typu zlyhanie a viacnásobná aplikácia funkcie (konštruktora)

Ján Kollár Funkcionálne programovanie 24 any :: (a -> Bool) -> [a] -> Bool any p = or. map p all :: (a -> Bool) -> [a] -> Bool all p = and. map p elem :: a -> [a] -> Bool x elem xs = any (x ==) xs reverse :: [a] -> [a] reverse = foldl (flip (:)) [] sp = sum. zipwith (*) flip :: (a -> b -> c) -> b -> a -> c flip f x y = f y x Nerekurzívne definície a funkcie vyššieho rádu

Ján Kollár Funkcionálne programovanie 25 1. [e 1..] generuje nekonečný zoznam počnúc od hodnoty výrazu e 1 s krokom +1. 2. [e 1, e 2..] generuje nekonečný zoznam počnúc od hodnoty výrazu e 1 s krokom e 2 e 1. 3. [e 1..e 3 ] generuje konečný zoznam počnúc od hodnoty výrazu e 1 v intervale e 1, e 3 s krokom +1. 4. [e 1, e 2..e 3 ] generuje konečný zoznam počnúc od hodnoty výrazu e 1 v intervale e 1, e 3 s krokom s krokom e 2 e 1. [ E Q 1,..., Q n ] :: [T ], ak E :: T MA ::= [ E QS ] QS ::= Q 1,..., Q n, pre n 0 Q ::= G F G ::= p <- L p ::= vzor Obr. 1: Syntax množinových abstrakcií Aritmetické postupnosti a množinové abstrakcie

Ján Kollár Funkcionálne programovanie 26 E [[ [ E qs ] ]] = C [[ [ E qs ] ]] C [[ [ E ] ]] = [ E [[ E ]] ] (1) C [[ [ E F, qs ] ]] = if (E [[ F ]] ) (C [[ [ E qs ] ]] ) ([ ]) (2) C [[ [ E F ] ]] = if (E [[ F ]] ) (C [[ [ E ] ]] ) ([ ]) (3) C [[ [ E p L, qs ] ]] = h (λp. C [[ [ E qs ] ]] ) (E [[ L ]] ) (4) C [[ [ E p L ] ]] = h (λp. C [[ [ E ] ]] ) (E [[ L ]] ) (5) Obr. 2: Schéma prekladu množinových abstrakcií kde qs je zoznam kvalifikátorov a h je h :: (a -> [b]) -> [a] -> [b] h f [] = [] h f (x:xs) = f x ++ h f xs Platí h f = concat. (map f) Preklad množinových abstrakcií

Ján Kollár Funkcionálne programovanie 27 concat :: [[a]] -> [a] concat xss = [x xs <- xss; x <- xs] map :: (a -> b) -> [a] ->[b] map f xs = [f x x <- xs] filter p xs = [x x <- xs; p x] zipwith :: (a -> b -> c) -> [a] -> [b] -> [c] zipwith f xs ys = [f x y (x,y) <- zip xs ys] sp xs ys = sum [x*y (x,y) <- zip xs ys] Použitie množinových abstrakcií

Ján Kollár Funkcionálne programovanie 28 data Btree a = Tip a Bin (Btree a) (Btree a) size (Tip x) = 1 size (Bin t1 t2) = size t1 + size t2 nsize (Tip x) = 0 nsize (Bin t1 t2) = 1 + size t1 + size t2 height (Tip x) = 0 height (Bin t1 t2) = 1 + (height t1) max (height t2) mapbtree :: (a->b) -> Btree a -> Btree b mapbtree f (Tip x) = Tip (f x) mapbtree f (Bin t1 t2) = Bin (mapbtree f t1) (mapbtree f t2) foldbtree :: (a->a->a) -> Btree a -> a foldbtree op (Tip x) = x foldbtree op (Bin t1 t2) = (foldbtree op t1) op (foldbtree op t2) sumtips = foldbtree (+) size = foldbtree (+). mapbtree (const 1) const :: a -> b -> a const k x = k height = foldbtree op. mapbtree (const 0) where d1 op d2 = 1 + (d1 max d2) tips = foldbtree (++). mapbtree unit where unit x = [x] data LBtree a b = Tip a Bin b (LBtree a b) (LBtree a b) -- binarny znackovany strom Binárne stromy

Ján Kollár Funkcionálne programovanie 29 data BStree a = Nil Bin a (BStree a) (BStree a) empty :: BStree a insert :: a -> BStree a -> BStree a delete :: a -> BStree a -> BStree a member :: a -> BStree a -> Bool Binárne vyhľadávacie stromy a množinové operácie

Ján Kollár Funkcionálne programovanie 30 empty = Nil insert x Nil = Bin x Nil Nil insert x (Bin y t1 t2) x < y = Bin y (insert x t1) t2 x == y = Bin y t1 t2 x > y = Bin y t1 (insert x t2) delete x Nil = Nil delete x (Bin y t1 t2) x < y = Bin y (delete x t1) t2 x == y = join t1 t2 x < y = Bin y t1 (delete x t2) join t1 t2 t1 == Nil = t2 otherwise = split t1 t2 split (Bin x t1 t2) t3 t2 == Nil = Bin x t1 t3 otherwise = Bin x t1 (split t2 t3) member x Nil = False member x (Bin y t1 t2) x < y = member x t1 x == y = True x > y = member x t2 labels Nil = [] labels (Bin x t1 t2) = labels t1 ++ [x] ++ labels t2 Implementácia množinových operácií

Ján Kollár Funkcionálne programovanie 31 sl Nil = 0 sl (Bin x t1 t2) = height t1 - height t2 Teraz možno def inovať funkciu rebal pre vyváženie stromu, pričom predpokladáme, že jeho podstromy sú vyvážené: rebal t sl t == 2 = shiftr t sl t == -2 = shiftl t otherwise = t Funkcie shiftr a shiftl def inujú posun stromu doprava, resp. ďoľava pomocou rotácií nasledovne: shiftr (Bin x t1 t2) sl t1 == -1 = rotr (Bin x (rotl t1) t2) otherwise = rotr (Bin x t1 t2) shiftl (Bin x t1 t2) sl t2 == 1 = rotl (Bin x t1 (rotr t2)) otherwise = rotl (Bin x t1 t2) rotr (Bin x (Bin y t1 t2) t3) = Bin y t1 (Bin x t2 t3) rotl (Bin x t1 (Bin y t2 t3)) = Bin y (Bin x t1 t2) t3 insert x Nil = Bin x Nil Nil insert x (Bin y t1 t2) x<y = rebal (Bin y (insert x t1) t2) x==y = Bin y t1 t2 x>y = rebal (Bin y t1 (insert x t2)) Vyvážené stromy

Ján Kollár Funkcionálne programovanie 32 data Gtree a = Node a [Gtree a] size (Node x gs) = 1 + sum (map size gs) height (Node x []) = 0 height (Node x (g:gs)) = 1 + maximum (map height (g:gs)) mapgtree :: (a -> b) -> Gtree a -> Gtree b mapgtree f (Node x gs) = Node (f x) (map (mapgtree f) gs) foldgtree :: (a -> a -> a) -> Gtree a -> a foldgtree f (Node x gs) = foldl f x (map (foldgtree f) gs) Všeobecné stromy

Ján Kollár Funkcionálne programovanie 33 abstr :: R A abstr :: List a [a] abstr Nil = [ ] abstr (Cons x xs) = x : abstr xs abstr :: Nat Int abstr Zero = 0 abstr (Succ x) = abstr x + 1 valid :: R Bool abstr :: [a] Set a abstr [ ] = {} abstr (x : xs) = {x} abstr xs valid1 xs = T rue valid2 xs = nodups xs valid3 xs = nodecs xs Abstraktné typy abstrakčná funkcia a predikát platnosti

Ján Kollár Funkcionálne programovanie 34 addset :: a Set a Set a addset x s = {x} s abstr (insert x xs) = addset x (abstr xs) abstr (insert x) = (addset x) abstr (abstr, valid1) (abstr, valid2) (abstr, valid3) insert1 x xs = [x] insert2 x xs = [x] ++ [y y<- xs, x /= y] insert3 x xs = takewhile (< x) xs ++ [x] ++ dropwhile (<= x) xs Príklad implementácie funkcie insert

Ján Kollár Funkcionálne programovanie 35 start :: Queue a join :: Queue a a Queue a front :: Queue a a reduce :: Queue a Queue a (1) f ront (join start x) = x (2) front (join (join q x) y) = front (join q x) (3) reduce (join start x) = start (4) reduce (join (join q x) y) = join (reduce (join q x)) y (5) Algebraická špecifikácia abstraktného typu front (Queue)

Ján Kollár Funkcionálne programovanie 36 data QUEUE a = Start Join (QUEUE a) a abstr :: QUEUE a Queue a abstr Start = start abstr (Join q x) = join (abstr q) x type QUEUE a = [a] abstr :: QUEUE a Queue a abstr [ ] = start abstr (x : xs) = join (abstr xs) x Príklad voľby rôznej reprezentácie údajov

Ján Kollár Funkcionálne programovanie 37 type QUEUE a = [a] class Queue a where start :: QUEUE a join :: QUEUE a -> a -> QUEUE a front :: QUEUE a -> a reduce :: QUEUE a -> QUEUE a isempty :: QUEUE a -> Bool mkqueue :: [a] -> QUEUE a instance Queue Int where start = [] join q x = q ++ [x] front q = head q reduce q = tail q instance Queue Char where start = [] join q x = q ++ [x] front q = head q reduce q = tail q isempty [] = True isempty (x:xs) = False mkqueue [] = start mkqueue (x:xs) = join (mkqueue (init (x:xs))) (last (x:xs)) instance Queue (a,b) where start = [] join q x = q ++ [x] front q = head q reduce q = tail q isempty [] = True isempty (x:xs) = False isempty [] isempty (x:xs) = True = False mkqueue [] = start mkqueue (x:xs) = join (mkqueue (init (x:xs))) (last (x:xs)) mkqueue [] = start mkqueue (x:xs) = join (mkqueue (init (x:xs))) (last (x:xs)) Implementácia abstraktného typu typová trieda a množina inštancií

Ján Kollár Funkcionálne programovanie 38 type QUEUE a = [a] class Queue a where start :: QUEUE a join :: QUEUE a -> a -> QUEUE a front :: QUEUE a -> a reduce :: QUEUE a -> QUEUE a isempty :: QUEUE a -> Bool mkqueue :: [a] -> QUEUE a -- definicia operacii pre vsetky instancie start = [] join q x = q ++ [x] front q = head q reduce q = tail q isempty [] = True isempty (x:xs) = False mkqueue [] = start mkqueue (x:xs) = join (mkqueue (init (x:xs))) (last (x:xs)) instance Queue Int instance Queue Char instance Queue (a,b) instance Queue Bool > start::queue Int [] > start::queue (Int,Char) [] > start::queue Char "" > reduce (join (join ( join (start::queue Char) a ) b ) c ) "bc" > front (join (join ( join (start::queue Char) a ) b ) c ) a > reduce (join (join ( join (start::queue Int) 10) 20) 30) [20,30] > front (join (join ( join (start::queue Int) 10) 20) 30) 10 > Špeciálny prípad implementácie abstraktného typu v jazyku Haskell a verifikácia

Ján Kollár Funkcionálne programovanie 39 class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b instance Monad IO where (>>=) = primbindio return = primretio return :: a -> IO a (>>=) :: IO a -> (a -> IO b) -> IO b 1. p 0 >>= \x 1 ->p 1 >>= \x 2 ->p 2 >>=... >>= \x (n 1) ->p (n 1) >>= \x n ->p n 2. do { x 1 <- p 0 ; x 2 <- p 1 ;... ; x n <- p (n 1) ; p n } (>>) :: Monad m => m a -> m b -> m b p >> q = p >>= \_ -> q (>>) :: IO a -> IO b -> IO b 1. p 0 >> p 1 >> p 2 >>... >> p (n 1) >> p n 2. p 0 >>= \ ->p 1 >>= \ ->p 2 >>=... >>= \ ->p (n 1) >>= \ ->p n 3. do { p 0 ; p 1 ;... ; p (n 1) ; p n } Používať formu zápisov 1., v žiadnom prípade nie do!!! Monadické operácie return, (>>=) a (>>) a ekvivalentné monadické väzby

Ján Kollár Funkcionálne programovanie 40 getchar :: IO Char getch :: IO Char getline :: IO String putchar :: Char -> IO () putstr :: String -> IO () putstrln :: String -> IO () readfile :: FilePath -> IO String writefile :: FilePath -> String -> IO () appendfile :: FilePath -> String -> IO () readbinaryfile :: FilePath -> IO String writebinaryfile :: FilePath -> String -> IO () appendbinaryfile :: FilePath -> String -> IO () import IOExtensions - len pre Hugs98 main = putstrln "Ahoj, ako sa volas?" >>= \x -> getline >>= \meno -> putstrln ("Ahoj " ++ meno ++ "!") > main Ahoj, ako sa volas? Jano Ahoj Jano! > Monadické funkcie pre vstup a výstup, príklad použitia

Ján Kollár Funkcionálne programovanie 41 Dokázať platnosť tvrdenia indukciou na zoznamoch znamená riešiť dva prípady: Prípad [ ]. Dokázať, že platí tvrdenie T([ ]). Prípad (x : xs). Dokázať nasledovné: Ak platí tvrdenie T(xs), potom platí aj tvrdenie T(x : xs). Príklad dôkaz platnosti vzťahu: take n xs ++ drop n xs = xs Prípad 0, xs. Pre tento prípad vzťah platí. Prípad n + 1, [ ]. Aj pre tento prípad vzťah platí. Prípad n + 1, (x : xs). take 0 xs ++ drop 0 xs = [ ] ++ xs (take.1, drop.1) = xs (++.1) take (n + 1) [ ] ++ drop (n + 1) [ ] = [ ] ++ [ ] (take.2, drop.2 ) = [ ] (++.1) take (n + 1) (x : xs) ++ drop (n + 1) (x : xs) = (x : take n xs) ++ drop n xs (take.3, drop.3 ) = x : (take n xs ++ drop n xs) (++.2) = x : xs (predpoklad) Vzhľadom na to, že vzťah platí aj pre tretí prípad, platí pre všetky prípustné hodnoty a teda je platný. Dokazovanie správnosti: dôkaz indukciou na zoznamoch

Ján Kollár Funkcionálne programovanie 42 data A a = N a S (A a) (A a)... (A a) Dokázať platnosť tvrdenia štrukturálnou indukciou znamená riešiť dva prípady: Prípad (N x). Dokázať, že platí tvrdenie T(N x). Prípad (N x 1 x 2... x n ). Dokázať nasledovné: Ak platia tvrdenia T(x 1 ), T(x 2 ),... T(x n ), potom platí aj tvrdenie T(N x 1 x 2... x n ). Príklad dôkaz platnosti size t 2ˆheight t Platí: size (T ip x) = 1 size (Bin t1 t2) = size t1 + size t2 Dôkaz: Prípad (T ip x). Platí: v súlade s predpokladom. height (T ip x) = 0 height (Bin t1 t2) = 1 + (height t1) max (height t2) size (T ip x) = 1 (size.1) = 2ˆ0 (ˆ.1) = 2ˆheight (T ip x) (height.1) Dokazovanie správnosti: dôkaz štrukturálnou indukciou

Ján Kollár Funkcionálne programovanie 43 Prípad (Bin t1 t2). Predpokladajme, vzhľadom na indukciu, že platí: size t1 2ˆheight t1 size t2 2ˆheight t2 a označme Potom platí: d = (height t1) max (height t2) size (Bin t1 t2) = size t1 + size t2 (size.2) (2ˆheight t1) + (2ˆheight t2) (predpoklad) (2ˆd) + (2ˆd) (dosadenie) = 2ˆ(1 + d) (výpočet) = 2ˆ(height (Bin t1 t2)) (height.2) Dokazovanie správnosti: dôkaz štrukturálnou indukciou pokračovanie

Ján Kollár Funkcionálne programovanie 44 init xs = take (length xs 1) xs, pre xs [ ] (6) Vzťah (6) je špecifikáciou a zároveň neefektívnou implementáciou. Efektívnejšiu implementáciu odvodíme tým, že odstránime funkcie take a length. (length) :: [a] Int length [ ] = 0 length (x : xs) = 1 + length xs Prípad [x]. init [x] = take (length [x] 1) [x] (dosadenie) = take (1 + length [] 1) [x] (length.2) = take (1 + 0 1) [x] (length.1) = take 0 [x] (výpočet) = [ ] (take.1) Výsledkom je rovnica Indukčný predpoklad je init [x] = [ ] init (x : xs) = take (length (x : xs) 1) (x : xs) Vzťah syntézy a dokazovania správnosti: syntéza

Ján Kollár Funkcionálne programovanie 45 Prípad (x : y : xs). init (x : y : xs) = take (length (x : y : xs) 1) (x : y : xs) (dosadenie) = take (1 + length (y : xs) 1) (x : y : xs) (length.2) = take (length (y : xs)) (x : y : xs) (výpočet) = x : take (length (y : xs) 1) (y : xs) (take.2) = x : init (y : xs) (predpoklad) Druhá rovnica implementácie (pre viac ako jednoprvkový zoznam) je v tvare: init (x : y : xs) = x : init (y : xs) takže odvodená implementácia v tvare výslednej rekurzívnej definície funkcie init je nasledovná: init [x] = [ ] init (x : y : xs) = x : init (y : xs) Vzťah syntézy a dokazovania správnosti: syntéza pokračovanie

Ján Kollár Funkcionálne programovanie 46 Prepokladajme teraz, že sme uvedenú funkciu neodvodili, ale priamo ju navrhli. V tom prípade prichádza do úvahy dôkaz platnosti tejto implementácie vo vzťahu na špecifikáciu (6), ktorý spočíva v dôkaze vzťahov init [x] = [ ], pre length [x] = 1 init (x : y : xs) = x : init (y : xs) pre length (x : y : xs) > 1 Dôkaz: Prípad [x]. pre jednoprvkové zoznamy init [x] = [ ] (dosadenie) = take 0 [x] (take.1) = take (length []) [x] (length.1 ) = take ((1 + length []) 1) [x] (úprava) = take (length [x] 1) [x] (length.2) Implementácia teda zodpovedá špecifikácii pre jednoprvkové zoznamy. Prípad (x : y : xs). pre všetky viac ako jednoprvkové zoznamy Indukčný predpoklad: init (x : xs) = take (length (x : xs) 1) (x : xs) init (x : y : xs) = x : init (y : xs) (dosadenie) = x : take (length (y : xs) 1) (y : xs) (predpoklad) = take (length (y : xs)) (x : y : xs) (take.2) = take ((1 + length (y : xs)) 1) (x : y : xs) (úprava) = take (length (x : y : xs) 1) (x : y : xs) (length.2) Implementácia teda zodpovedá špecifikácii aj pre viac ako jednoprvkové zoznamy, a teda je správna. Záver: Dôkaz platnosti pre program syntetizovaný matematickými metódami nemá význam robiť. Vzťah syntézy a dokazovania správnosti: dôkaz platnosti

Ján Kollár Funkcionálne programovanie 47 Def inícia 1: Abstraktná syntax jazyka lambda E ::= k konštanta v meno premennej E E aplikácia λv.e abstrakcia lambda incr x = x + 1 (λ(x).(((+) (x)) (1))) add x y = x + y (λ(x).(λ(y).(((+) (x)) (y)))) incr = λx. + x 1 add = λx.λy. + x y Syntax jazyka lambda a príklady vyjadrenia funkcií v jazyku lambda

Ján Kollár Funkcionálne programovanie 48 Def inícia 2: Voľná premenná 1. Premenná x je voľná v premennej x (nie však v konštante alebo inej premennej). 2. Premenná x je voľná v aplikácii (E F ) práve vtedy, ak je voľná vo výraze E alebo je voľná vo výraze F. 3. Premenná x je voľná v abstrakcii (λy.e) práve vtedy, ak x a y sú rôzne premenné a x je voľná v E. Def inícia 3: Viazaná premenná 1. Premenná x je viazaná v aplikácii (E F ) práve vtedy, ak je viazaná v E a zároveň je viazaná v F. 2. Premenná x je viazaná v abstrakcii (λy.e) práve vtedy, ak x a y sú tie isté premenné a x je voľná v E alebo ak x je viazaná v E. Vo výraze (λx. + x y) 4 je premenná x viazaná, y je voľná. Operačná sémantika jazyka lambda: voľné a viazané premenné

Ján Kollár Funkcionálne programovanie 49 Def inícia 4: Substitúcia E[M/x] Ak x, y a z sú premenné, c je premenná alebo konštanta rôzna od x, a E, F a M sú výrazy lambda, potom substitúcia E[M/x] je def inovaná nasledovne: x [M/x] = M c [M/x] = c (E F ) [M/x] = E[M/x] F [M/x] (λx.e) [M/x] = λx.e (λy.e) [M/x] = λy.e[m/x], ak x nie je voľná v E alebo y nie je voľná v M = λz.(e[z/y]) [M/x], v opačnom prípade,, kde z je nová premenná, ktorá nie je voľná v E a M Operačná sémantika jazyka lambda: substitúcia E[M/x]

Ján Kollár Funkcionálne programovanie 50 Definícia 5: Zámena alfa Ak y nie je voľná v E, potom platí: (λx. E) λy. E[y/x] Def inícia 6: Zámena beta (λx.e) M E[M/x] Definícia 7: Zámena eta Ak x nie je voľná v E a E je funkcia, potom: (λx.e x) E Zámeny beta a eta použité zľava doprava ( ) sa nazývajú redukcie. Predpoklad zámeny eta dovoľuje napríklad redukciu eta, ktorou je odstránená nadbytočná abstrakcia lambda (λx. + 1 x) + 1 lebo (+ 1) je funkcia, ktorá neobsahuje x. Na druhej strane redukcia eta (λx. + x x) + x nie je platná, lebo (+ x) je síce funkcia, ale obsahuje x. Operačná sémantika jazyka lambda: pravidlá zameniteľnosti výrazov

Ján Kollár Funkcionálne programovanie 51 1. Redukcia beta: (λx 1.λx 2... λx n.e) F λx 2... λx n. E[F/x 1 ] kde E[F/x 1 ] označuje výraz E, v ktorom všetky výskyty premennej x 1 sú nahradené výrazom F, je platná, ak voľné premenné argumentu F nie sú identické so žiadnym z formálnych parametrov x 1, x 2,..., x n tela E abstrakcie lambda: λx 1.λx 2... λx n. E 2. Zámena alf a: λx. E λy. E[x/y] je platná, ak nové meno y nie je identické s voľnou premennou výrazu E. (λx.λy. + x y) y 2 (λy. + y y) 2 + 2 2 4 redukcia beta a kolízia y je chybný výsledok. Operačná sémantika jazyka lambda: problém kolízie mien

Ján Kollár Funkcionálne programovanie 52 Veta 1: Church-Rosserova veta I Ak E 1 E 2, potom existuje výraz E taký, že platí: E 1 E a súčasne E 2 E Žiadny výraz nemožno redukovať do dvoch rôznych normálnych foriem (t.j. alf a-nekonvertibilných). Dôkaz: Predpokladajme, že E E 1 a E E 2, kde E 1 a E 2 sú v normálnej forme. Potom E 1 E 2 a podľa Church-Rosserovej vety I musí existovať výraz F taký, že platí: E 1 F a súčasne E 2 F Vzhľadom na to, že E 1 a E 2 neobsahujú žiadny redukovateľný výraz, platí E 1 = F = E 2. Veta 2: Church-Rosserova veta II Ak E 1 E 2, a E 2 je v normálnej forme, potom existuje normálne poradie postupnosti redukcií z E 1 do E 2. Normálne poradie redukcie určuje, že prvý bude redukovaný vonkajší (najvrchnejší) výraz zľava, napr.: (λx.(λy.( x y))) (+ 3 4) ( 5 2) (λy.( (+ 3 4) y)) ( 5 2) ( (+ 3 4) ( 5 2)) ( 7 ( 5 2)) ( 7 3) 21 Church-Rosserove vety a normálne poradie redukcie

Ján Kollár Funkcionálne programovanie 53 Vonkajšia redukcia zľava. Je to normálne poradie redukcie. Vnútorná redukcia zľava. Výber redukovateľného výrazu sa uskutočňuje sekvenčne zľava, avšak vyžaduje sa, aby aj funkcia aj jej argument boli v normálnej forme. Vonkajšia paralelná redukcia. Všetky redukovateľné výrazy, ktoré nie sú vnorené v iných výrazoch, sú vybraté naraz a naraz sú redukované. Vnútorná paralelná redukcia. Všetky redukovateľné výrazy, ktoré neobsahujú redukovateľné výrazy sú vyberané a redukované súčasne. Úplná paralelná redukcia. Všetky redukovateľné výrazy sú redukované naraz. Táto stratégia je veľmi komplikovaná, keďže výrazy môžu byť vnorené. Ak aj existuje normálna forma, vnútornou stratégiou redukcie nie je vždy dosiahnuteľná, t.j. výpočet nemusí skončiť. Ako príklad možno uviesť vnútornú redukciu: (λy. c) ((λx. x x x) (λx. x x x)) (λy. c) ((λx. x x x) (λx. x x x) (λx. x x x)) (λy. c) ((λx. x x x) (λx. x x x) (λx. x x x) (λx. x x x)) ktorá vedie k expanzii výrazu ((λx. x x x) (λx. x x x)) pričom pri vonkajšej redukcii možno okamžite v prvom kroku získať normálnu formu c. (λy. c) ((λx. x x x) (λx. x x x)) c Stratégie redukcie výrazu

Ján Kollár Funkcionálne programovanie 54 Def inícia 8: Slabá pref ixná normálna forma Výraz lambda je v slabej prefixnej normálnej forme práve vtedy, keď je v tvare: F E 1 E 2... E n kde n 0 a F je buď premenná alebo údajový objekt, alebo F je abstrakcia lambda alebo operátor a zároveň F E 1 E 2 je redukovateľný výraz pre m n.... E m nie Výraz neobsahuje žiadny vrcholový redukovateľný výraz vtedy a len vtedy, ak je v slabej prefixnej normálnej forme. Def inícia 9: Pref ixná normálna forma Výraz lambda je v prefixnej normálnej forme práve vtedy, keď je v tvare: λx 1.λx 2.... λx n. v M 1 M 2... M m kde n, m 0 a v je premenná x i, údajový objekt alebo operátor a (v M 1 M 2... M p ) nie je redukovateľný výraz pre p m. Každý výraz v pref ixnej normálnej forme je zároveň výrazom v slabej pref ixnej normálnej forme, ale nie naopak. Normálne formy výrazu

Ján Kollár Funkcionálne programovanie 55 Funkcia f: f = λx. E je rekurzívna, ak obsahuje premennú f v svojom tele E. Pomocou abstrakcie beta ju možno vyjadriť nasledovne: f = (λx. E) (λn.λx. E[n/f]) f = H f kde H = λn.λx. E[n/f] je abstrakcia lambda, ktorá neobsahuje f vo výraze E[n/f], je to teda nerekurzívna funkcia. Potom rovnica: f = H f (7) znamená, že ak H sa aplikuje na f, výsledok ostáva f, a preto je f pevným bodom funkcie H. Funkcia môže mať aj viac pevných bodov, napr. 0 a 1 sú pevné body funkcie λx. x x Funkcia Y, nazývaná tiež kombinátorom pevného bodu je funkcia, ktorá vypočíta pevný bod, keď je aplikovaná na H (pretože pevný bod f závisí jedine od H). Teda platí: f = Y H (8) a po dosadení do rovnice (7) Y H = H (Y H) (9) Pritom kombinátor pevného bodu Y je def inovaný nasledovne: Dosadením do (9) možno preveriť správnosť def inície (10). Y = (λh.(λx. h (x x)) (λx. h (x x))) (10) Vyjadrenie rekurzívnych funkcií v netypovanom jazyku lambda

Ján Kollár Funkcionálne programovanie 56 Def inícia kombinátora Y je nerekurzívna a teda umožňuje vyjadriť rekurzívnu funkciu f pomocou aplikácie nerekurzívneho kombinátora pevného bodu Y na funkciu H, ktorá je tiež nerekurzívna. Napr. rekurzívnu funkciu fac k = 1, if k = 0 = k f ac (k 1), otherwise vyjadrenú vo formálne nesprávnom (a rekurzívnom) tvare fac = λk. IF (= k 0) 1 ( k (fac ( k 1))) je možné vyjadriť správne a nerekurzívne nasledovne: fac = (λh. (λx. h (x x)) (λx. h (x x))) (λn.λk. IF (= k 0) 1 ( k (n ( k 1)))) Implementácia rekurzívnych funkcií na báze rozšíreného jazyka lambda nevyžaduje uplatnenie kombinátora Y. Vyjadrenie rekurzívnych funkcií v netypovanom jazyku lambda pokračovanie

Ján Kollár Funkcionálne programovanie 57 Eval [[ k ]] hodnota konštanty Eval [[ x ]] ρ = ρ x Eval [[ E 1 E 2 ]] ρ = (Eval [[ E 1 ]] ρ) (Eval [[ E 2 ]] ρ) Eval [[ λx.e ]] ρ a = Eval [[ E ]] ρ[x = a] kde k je konštanta alebo operátor x je premenná a je hodnota E, E 1, E 2 sú výrazy ρ je prostredie, t.j. funkcia zobrazujúca mená premenných do ich hodnôt Platí ρ[x = a] x = a ρ[x = a] y = ρ y kde ρ[x = a] je funkcia ρ, ktorá má premennú x viazanú na hodnotu a. Definícia 10: Symbol Symbol označuje nedef inovanú hodnotu a je def inovaný nasledovne: Eval [[ E ]] = kde E je výraz, ktorý nemá normálnu formu. Denotačná sémantika jazyka lambda

Ján Kollár Funkcionálne programovanie 58 Def inícia 11: Striktná funkcia Funkcia f je striktná vzhľadom na svoj argument práve vtedy, ak platí: f = Def inícia 12: Nestriktná funkcia Funkcia f je nestriktná vzhľadom na svoj argument práve vtedy, ak platí: f = a Striktnosť a nestriktnosť funkcie definícia

Ján Kollár Funkcionálne programovanie 59 Eval [[ ]] T rue T rue = T rue Eval [[ ]] T rue F alse = T rue Eval [[ ]] F alse T rue = T rue Eval [[ ]] F alse F alse = F alse Eval [[ ]] T rue = T rue Eval [[ ]] T rue = T rue Eval [[ ]] F alse = Eval [[ ]] F alse = Eval [[ ]] = Eval [[ IF ]] T rue a b = a Eval [[ IF ]] F alse a b = b Eval [[ IF ]] a b = Eval [[ < ]] x y = x < y, ak x a y Eval [[ < ]] y = Eval [[ < ]] x = Eval [[ / ]] x y = x/y, ak x a y a y 0 Eval [[ / ]] x y =, ak x a y a y = 0 Eval [[ < ]] y = Eval [[ < ]] x = Striktnosť a nestriktnosť funkcie príklady

Ján Kollár Funkcionálne programovanie 60 Všeobecne platí: Eval [[ k ]] = k kde k na ľavej strane je konštanta ako syntaktický objekt a k na pravej strane je hodnota konštanty (čísla, operátora alebo konštruktora). Napríklad: Eval [[ 3 ]] = 3 ; numerická konštanta Eval [[ a ]] = a ; znaková konštanta Eval [[ IF ]] = IF ; operátor Eval [[ + ]] = + ; operátor Eval [[ T rue ]] = T rue ; konštruktor Eval [[ Nil ]] = Nil ; konštruktor Eval [[ Cons ]] = Cons ; konštruktor Sémantika konštanty a operátora

Ján Kollár Funkcionálne programovanie 61 Def inícia 13: Výpočet na základe hodnoty Základným princípom tohto výpočtu je mechanizmus, pri ktorom hodnoty argumentov funkcie musia byť vypočítané predtým, ako je funkcia aplikovaná. Ide o princíp vnútornej redukcie. Odovzdávanie skutočných parametrov je realizované hodnotou (callby-value). Def inícia 14: Výpočet na základe požiadavky Pre tento výpočet je charakteristické, že hodnoty argumentov funkcie sú vypočítané až na základe požiadavky. Ide teda o princíp vonkajšej redukcie. Odovzdávanie skutočných parametrov je realizované menom (call-by-name). Nestriktnosť je matematickou vlastnosťou funkcie (operácie) a výpočet na základe požiadavky je jej výhodným sekvenčným implementačným mechanizmom, pretože neužitočný výraz netreba vôbec počítať. Princíp výpočtu na základe požiadavky a hodnoty

Ján Kollár Funkcionálne programovanie 62 Def inícia 15: Superkombinátor Superkombinátor $S násobnosti n je výraz lambda v tvare: $S = λx 1.λx 2.... λx n. E kde E nie je abstrakcia lambda, taký, že platí 1. $S neobsahuje voľné premenné 2. Každá abstrakcia lambda vo výraze E je superkombinátorom 3. n 0 Kombinátor je špecif ickým výrazom lambda a superkombinátor je špecif ickým kombinátorom. Transformácia do superkombinátorovej formy znamená odstránenie voľných premenných. Algoritmus, pomocou ktorého je to možné dosiahnuť, sa nazýva λ lifting. Kombinátory superkombinátory

Ján Kollár Funkcionálne programovanie 63 Pravidlá pre transformáciu abstrakcií lambda do kombinátorov SK sa nazývajú transformácie S, K a I, a sú nasledovné: (λx.e 1 e 2 ) S (λx.e 1 ) (λx. e 2 ) (λx.c) K c (c x) (λx.x) I Napríklad nech funkcia h je vyjadrená nasledovnou abstrakciou lambda: h = λx. OR x T RUE kde OR a T RU E sú konštanty. Dvojnásobným použitím transformácie S dostaneme: (λx. OR x T RUE) S S (λx. OR x) (λx. T RUE) S S (S (λx. OR) (λx. x)) (λx. T RUE) Ďalej použitím transformácie I a K dostaneme výsledok nasledovne: ((S (λx. OR) (λx. x)) (λx. T RUE)) I S (S (λx. OR) I) (λx. T RUE) K S (S (K OR) I) (λx. T RUE) K S (S (K OR) I) (K T RUE) Funkciu h teda možno vyjadriť v tvare kombinátorov S, K a I nasledovne: h = S (S (K OR) I) (K T RUE) Kombinátory SK transformácia výrazu lambda

Ján Kollár Funkcionálne programovanie 64 Redukčné pravidlá pre kombinátory S, K, a I sú nasledovné: S f g x f x (g x) K c y c I x x Príklad redukcie výrazu (h y): čo skutočne zodpovedá výrazu (h y) = S (S (K OR) I) (K T RUE) y S S (K OR) I y (K T RUE y) S K OR y (I y) (K T RUE y) K OR (I y) (K T RUE y) I OR y (K T RUE y) K OR y T RUE (λx. OR x T RUE) y po redukcii beta. Nazáver možno ukázať, že kombinátor I možno nahradiť výrazom (S K K) a teda kombinátor I je nadbytočný. Ak aplikujeme výraz (S K K) na výraz x dostaneme výraz x: čo zodpovedá aplikácii I na x: Výraz (S K K) je teda ekvivalentný kombinátoru I. (S K K) x S K x (K x) K x I x I x Kombinátory SK redukcia výrazu v tvare kombinátorov SK

FUNKCIONÁLNE PROGRAMOVANIE c prof. Ing. Ján Kollár, CSc. Katedra počítačov a informatiky Fakulta elektrotechniky a informatiky Technická univerzita v Košiciach 2016 65