Download de presentatie
De presentatie wordt gedownload. Even geduld aub
GepubliceerdKlaas Smeets Laatst gewijzigd meer dan 9 jaar geleden
1
(S)DT 2012-2013 1 Haskell Deel 2 list comprehensions, types en type klassen, programma transformatie, I/O
2
LIST COMPREHENSIONS (S)DT 2012-2013 2
3
3 List comprehension Main> [ 2*a | a <- [2,3,8] ] [4,6,16] lezen we als de lijst met waarden 2*a met a geselecteerd uit de lijst [2,3,8] -- <- generator l = take 10 [ x*x | x <- (odds [1..])] where odds [] = [] odds (x:xs) | x `mod` 2 == 1 = (x : odds xs) | True = (odds xs) Main> l [1,9,25,49,81,121,169,225,289,361]
4
(S)DT 2012-2013 4 Nog list comprehensions Main> let l = [2,4,7] in [ a > 4 | a <-l] [False,False,True] Main> let l = [8,2,4,7] in [a | a 4] [8,7] -- generator en test Main> take 10 [ x*x | x <- [1..], x `mod` 2 == 1] [1,9,25,49,81,121,169,225,289,361] Main> let l= [ [], [1], [4,5], []] in [ a | (a:x) <-l] [1,4] Main> let l = [ (1,2), (4,3)] in [ a+b| (a,b) b] [7]
5
(S)DT 2012-2013 5 Variabelen in list comprehensions Main> let l = [(1,2), (4,3)] in [b | (1,b) <- l] [2] Main> let l = [(1,2), (3,3)] in [b | (b,b) <- l] ERROR - Repeated variable "b" in pattern -- scope van variabelen f x l = [ a | (x,a) <- l] -- nieuwe x g x l = [ a | (y,a) <- l, x == y] Main> f 1 [(1,2), (4,3)] [2,3] Main> g 1 [(1,2), (4,3)] [2]
6
(S)DT 2012-2013 6 Verschillende generatoren Main> [ (a,b) | a <- [1..2], b <- [1..3]] [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3)] Main> [ (a,b) | b <- [1..3], a <- [1,2]] [(1,1),(2,1),(1,2),(2,2),(1,3),(2,3)] Main> let l = [(2,7), (4,3)] -- b is afhankelijk in [(a,b)| (a,_) <- l, b <- [1..a]] [(2,1),(2,2),(4,1),(4,2),(4,3),(4,4)] -- Een Pythagorees drietal (a, b, c) bestaat uit drie positieve gehele getallen a, b, c met a < b < c waarvoor geldt a 2 + b 2 = c 2positievegehele getallen
7
(S)DT 2012-2013 7 Algemene vorm [ e | q1, q2, …, qn] qi is (pattern <- listexpr) of (boolean expr) vars in qi moeten links ervan voorkomen elke var in een pattern is nieuw! Schrijf map f (filter p xs) nu met list comprehension En eventueel ook qsort
8
(S)DT 2012-2013 8 Opnieuw priem priemgetallen n = [ x | x <- [1..n], priem x] priem x = factors x == [1,x] factors n = [ x | x <- [1..n], n `mod` x == 0]
9
TYPES Data declaraties; Polymorfe types; Type klassen (S)DT 2012-2013 9
10
10 Welke types kennen we? Int, Integer [Int] (Bool, Int) type variabele t,a,b lengthlist :: [t] -> Int map :: (a->b) -> [a] -> [b] Char ‘a’ String “hallo world” in feite synoniem voor lijst van Char type String = [Char] type Positie = (Int,Int)
11
(S)DT 2012-2013 11 Data declaratie voor type IBoom data IBoom = Knoop IBoom IBoom | Blad Int -- wat zijn de mogelijke waarden van het type IBoom? -- Knoop (Blad 4) (Knoop (Blad 3) (Blad 100)) balanced :: IBoom -> Bool balanced (Knoop left right) = let l = diepte left r = diepte right in (ok l r ) && (balanced left) && (balanced right) balanced (Blad _) = True ok :: Int -> Int -> Bool ok l r = (l==r) || (l == (r+1)) || ( (l+1) == r)
12
(S)DT 2012-2013 12 diepte :: IBoom -> Int diepte (Knoop l r) = 1 + maxi (diepte l) (diepte r) diepte (Blad _) = 1 maxi :: Int -> Int -> Int maxi x y | x > y = x | otherwise = y
13
(S)DT 2012-2013 13 Ingebouwde types data Bool = True | False -- enumeratie -- Bool is een nieuw type met 2 mogelijke waarden -- constructor-functies: True en False data Int = 0 | 1 | -1 | 2 | -2 | 3 …
14
(S)DT 2012-2013 14 Meer types Record type data Punt = Coord Int Int -- Coord als data constructor data Punt = Punt Int Int -- Verschil?? data Punt = MkPunt Int Int -- Verschil?? Hoe: Int of Bool Constructors worden gebruikt: Als een functie om waarden aan te maken (in rechter deel van equations) In patronen om waarden af te breken (in linker deel van equations)
15
(S)DT 2012-2013 15 Polymorfe types data Boom a =Knoop (Boom a) (Boom a)|Blad a Voor elk type a is (Boom a) een data type Boom is een typeconstructor Knoop is een dataconstructor – of een constructor functie Main> :t Knoop Knoop :: Boom a -> Boom a -> Boom a Main> :t Blad Blad :: a -> Boom a
16
(S)DT 2012-2013 16 Bladeren bladeren :: Boom a -> [a] bladeren (Knoop l r) = bladeren l ++ bladeren r bladeren (Blad b) = [b] -- Nog een ingebouwd (polymorf) datatype … data [a] = [] | a : [a]
17
(S)DT 2012-2013 17 Werkvoorbeeld polymorfisme isort :: [Int] -> [Int] isort [] = [] isort (x:xs) = insert x (isort xs) insert :: Int -> [Int] -> [Int] insert x [] = [x] insert x (y:ys) | x<y = x:y:ys | otherwise = y : (insert x ys) -- polymorfe versie?? door ??? -- Int vervangen door ???
18
(S)DT 2012-2013 18 Polymorfe isort isort :: (t -> t -> Bool) -> [t] -> [t] isort _ [] = [] -- was isort (x:xs) = insert x (isort xs) isort orde (x:xs) = insert orde x (isort orde xs) insert :: (t -> t -> Bool) -> t -> [t] -> [t] insert _ x [] = [x] insert orde x (y:ys) | (orde x y) = x:y:ys | otherwise = y : (insert orde x ys) Main> isort (<) [3,1,7] [1,3,7]
19
(S)DT 2012-2013 19 Evaluatie: wat gedaan? extra parameter (de functie) doorgeven – eventueel diep de type declaraties aanpassen code aanpassen de waarde van die parameter is gekend op moment van de topoproep de waarde (naam van de functie) kan afhankelijk zijn van het type Misschien is het handiger om uit te drukken: isort mag enkel op een lijst met elementen waarop (<) gedefineerd is
20
(S)DT 2012-2013 20 Overloading wat is overloading?? ad-hoc polymorfisme voorbeeld : een zelfde operator + kan gebruikt worden voor verschillende types van operanden (Int, Float) en de definitie van + is type-afhankelijk dezelfde naam maar verschillende operaties op verschillende types wat is het type van square n = n*n ?
21
(S)DT 2012-2013 21 Type classes: uitbreidbare overloading class HeeftOrde a where -- klasse-declaratie ( a -> Bool isort :: (HeeftOrde t) => [t] -> [t] -- klasse-constraint isort [] = [] isort (x:xs) = insert x (isort xs) insert :: (HeeftOrde t) => t -> [t] -> [t] insert x [] = [x] insert x (y:ys) | x <<< y = x:y:ys | otherwise = y: (insert x ys)
22
(S)DT 2012-2013 22 Klasse-constraint insert :: (HeeftOrde t) => t -> [t] -> [t] insert x [] = [x] insert x (y:ys) | x <<< y = x:y:ys | otherwise = y: (insert x ys) zonder klasse-constraint zegt Haskell: ERROR "cl.hs":12 - Cannot justify constraints in explicitly typed binding *** Expression : insert *** Type : a -> [a] -> [a] *** Constraints : HeeftOrde a Main> isort [2,1] ERROR - Unresolved overloading *** Type : (Num a, HeeftOrde a) => [a] *** Expression : isort [2,1]
23
(S)DT 2012-2013 23 Instance van een klasse data Dagen = Maan | Dins | Woen | Dond |Vrij instance HeeftOrde Dagen where Maan <<< _ = True _ <<< Maan = False Dins <<< _ = True _ <<< Dins = False Woen <<< _ = True _ <<< Woen = False Dond <<< _ = True _ <<< _ = False Main> isort [Maan, Woen, Dins] [Maan,Dins,Woen]
24
(S)DT 2012-2013 24 Dus nu met type classes geen extra parameters geen code aanpassen type declaratie aanpassen – eventueel diep het type van de polymorfe parameter is gekend op moment van de topoproep de compiler kan achter de schermen de vergelijkingsfunctie meegeven (en doet dat) de naam van de functie is voor alle instances van de klasse dezelfde. Gelijkenis met interface van Java?
25
(S)DT 2012-2013 25 Wat hebben we? Een type klasse is een groep van types (instances) waarop bepaalde functies kunnen worden toegepast (vergelijk met polymorf type) Type klassen laten toe om de parameters van de polymorfe types/functies verder te beperken Bv. type parameter a, maar == gedefinieerd voor a Type klassen en instanties worden gebruikt voor het checken van de types tijdens compilatie. Type klassen hiërarchie: class (Eq a) => Ord a where … -- Ord is een subklasse, erft van Eq
26
(S)DT 2012-2013 26 Dus Een type klasse beschrijft een “concept” Een type kan een instance zijn van een type klasse en is dan een implementatie van het “concept”. Generische programma’s mogelijk dankzij Parametrisch polymorfisme Type constraints (zie context) In Java, concept als “interface” En een Java class implements interface
27
(S)DT 2012-2013 27 Ingebouwde klassen uit Prelude class Eq a where (==), (/=) :: a -> a -> Bool x /= y = not (x==y) -- default definitie class (Eq a) => Ord a where -- class extension compare :: a -> a -> Ordering ( =), (>) :: a -> a -> Bool compare x y | x == y = EQ | x <= y = LT | otherwise = GT x <= y = compare x y /= GT x < y = compare x y == LT
28
(S)DT 2012-2013 28 Ingebouwde instanties data Bool = False | True instance Eq Bool where True == True = True False == False = True _ == _ = False instance Ord Bool where False <= True = True _ <= _ = False
29
(S)DT 2012-2013 29 Eenvoudig instanties maken Er is dikwijls een natuurlijke implementatie voor de functies in een klasse data Bool = False | True deriving (Eq, Ord, Show, … ) Is elk type een instance van Eq? Door er deriving Eq bij te zetten? Waarom mag dezelfde variabele niet tweemaal in een pattern match?
30
(S)DT 2012-2013 30 De klasse Num class (Eq a, Show a) => Num a where (+), (-), (*) :: a -> a -> a negate :: a -> a abs, signum :: a -> a fromInteger :: Integer -> a fromInt :: Int -> a x - y = x + negate y fromInt = fromIntegral negate x = 0 - x Main> :t square square :: Num a => a -> a
31
(S)DT 2012-2013 31 Int als instance van Num -- Int is builtin datatype of fixed size integers primitive primEqInt :: Int -> Int -> Bool instance Eq Int where (==) = primEqInt instance Num Int where (+) = primPlusInt -- ingebouwd prim… (-) = primMinusInt negate = primNegInt fromInteger n = n
32
(S)DT 2012-2013 32 Type klassen en type inferentie De type inferentie leidt het meest algemene type af. Daarin komen dikwijls type constraints voor (+) :: Num a => a -> a -> a (/) :: Fractional a => a -> a -> a
33
(S)DT 2012-2013 33 Instances met voorwaarden -- data [a] = [] | a : [a] deriving (Eq, Ord) instance Eq a => Eq [a] where -- context!! [] == [] = True (x:xs) == (y:ys) = x == y && xs == ys -- welke? _ == _ = False
34
(S)DT 2012-2013 34 de klasse Text ERROR - Cannot find "show" function for: *** Expression : isort [Maan,Woen,Dins] *** Of type : [Dagen] class Show a where show :: a -> String data Dagen = Maan | Dins | Woen | Dond |Vrij deriving Show Main> show Maan “Maan”
35
(S)DT 2012-2013 35 Enkele vragen Wat is het meest algemene type van elem 1 [ 2, 4, 9] False elem ‘a’ “Harry” True En van allevk a [] = [] allevk a ((x,y): rest) = if a == x then y : allvk a rest else allevk a rest En van qsort ??
36
(S)DT 2012-2013 36 Nog enkele vragen Herinner je het type Boom a data Boom a = Knoop (Boom a) (Boom a)| Blad a Hoe een gelijkheidstest definieren? Type declaratie van de functie element?? Eindige set (wat is een set??) voorgesteld als een lijst Type declaratie Voegtoe, unie, element? Gelijkheid van 2 sets?
37
Meer info over classes In TasteofHaskell.pdf : slides 43-63 (S)DT 2012-2013 37
38
PROGRAMMA TRANSFORMATIE Equational reasoning (S)DT 2012-2013 38
39
(S)DT 2012-2013 39 reverse en reverse nrev [] = [] nrev (x:xs) = nrev xs ++ [x] [] ++ l = l (x:xs) ++ l = (x : (xs ++ l)) reverse l = rev2 l [] rev2 [] a = a -- (a) rev2 (x:xs) a = rev2 xs (x:a) -- (b) nrev is O( n**2) – reverse is O(n)
40
(S)DT 2012-2013 40 Automatisch van nrev naar reverse vertrek van de invariant voor alle l : rev2 l a = (nrev l) ++ a gebaseerd op het type van l, herschrijf tot: voor l== [] of l==(x:xs): rev2 l a = (nrev l) ++ a of zonder quantoren 1. rev2 [] a = (nrev [] ) ++ a 2. rev2 (x:xs) a = (nrev (x:xs)) ++ a we bewijzen achtereen volgens (a) en (b)
41
(S)DT 2012-2013 41 Te bewijzen: rev2 [] a = a rev2 [] a = (nrev []) ++ a -- (1) = [] ++ a -- gebruik 1ste regel nrev = a -- 1ste regel van ++ We hebben (a) bewezen en gebruikten de invariant en partiële evaluatie
42
(S)DT 2012-2013 42 Te bewijzen rev2 (x:xs) a = rev2 xs (x:a) rev2 (x:xs) a = (nrev (x:xs)) ++ a -- (2) = ( (nrev xs) ++ [x]) ++ a -- gebruik 2e regel nrev = (nrev xs) ++ ([x] ++ a) -- ++ is associatief = (nrev xs) ++ (x : a) -- regels van ++ = rev2 xs (x:a) -- invariant omgekeerd We hebben (b) bewezen en gebruikten de invariant en partiële evaluatie en de associativiteit van ++ (nog te bewijzen)
43
(S)DT 2012-2013 43 Te bewijzen (a ++ b) ++ c = a ++ (b ++ c) Inductie op lengte van a: a kan [] zijn of (x:xs) Basis van de inductie: a = [] ([] ++ b ) ++ c = b ++ c -- regel 1 van ++ Inductiestap: stel associativiteit is waar voor a == xs, bewijs dat associatviteit is waar voor a = (x:xs)
44
(S)DT 2012-2013 44 Associativiteit: inductiestap x:xs 2e regel : (x:xs) ++ l = (x : (xs ++ l)) (a ++ b ) ++ c = ( (x:xs) ++ b) ++ c -- a == (x:xs) = ( x : (xs ++ b) ) ++ c -- regel 2 van ++ = x : ( (xs ++ b) ++ c) -- regel 2 van ++ = x : ( xs ++ (b ++ c)) -- asso. Door inductie = (x : xs) ++ (b ++ c) -- omgekeerde regel 2 ++ = a ++ (b ++ c) -- a == (x:xs)
45
I/O HASKELL (S)DT 2012-2013 45
46
(S)DT 2012-2013 46 I/O in pure Haskell heeft geen zin want referential transparency: 2x oproepen, 2x zelfde resultaat luiheid: op welk ogenblik wordt een functie uitgevoerd? Hoe zinvol aan I/O doen in Haskell? de toestand van de wereld is een impliciet argument van functies die I/O doen sequentialisatie van I/O acties
47
(S)DT 2012-2013 47 I/O ondersteuning door type systeem en nieuwe syntactische constructie – do getChar :: IO Char putChar :: Char -> IO () Een waarde van type IO t is een “action” die, als ze wordt uitgevoerd, mogelijks wat I/O doet voor een resultaat van type t te geven. Dus wat leiden we af uit het type van putChar ?
48
Achterliggend idee Een waarde van type IO t is een “action” die, als ze wordt uitgevoerd, mogelijks wat I/O doet voor een resultaat van type t te geven. type IO t = World -> (t,World) -- een benadering!!! (S)DT 2012-2013 48 World inWorld out I/O t result :: t
49
(S)DT 2012-2013 49 Voorbeeld I/O en do-notatie Een functie die een Int als argument heeft, IO doet en een string teruggeeft: n chars worden gelezen en omgekeerd als string teruggegeven foo :: Int -> IO String foo n = do a <- getnchars n [] return a getnchars :: Int -> String -> IO String getnchars 0 l = return l getnchars (n+1) l = do a <- getChar s <- getnchars n (a:l) return s -- return :: a -> IO a -- do maakt 1 actie van een sequentie van acties
50
(S)DT 2012-2013 50 Een functie f doet IO f heeft als return type IO iets als g f oproept, dan doet g IO en heeft type IO iets’ f roept minstens 1 functie op die IO doet en kan functies oproepen die dat niet doen waarde van iets kan opgevangen worden door de constructie <- do dient om IO te sequentialiseren
51
(S)DT 2012-2013 51 Voorbeeld opnieuw foo :: Int -> IO String foo n = do a <- getnchars n return (rev a) getnchars :: Int -> IO String getnchars 0 = return [] getnchars (n+1) = do a <- getChar s <- getnchars n return (a:s)
52
(S)DT 2012-2013 52 Waarden van het type (IO t) zijn first class forever :: IO () -> IO () forever a = do { a; forever a } repeatN :: Int -> IO () -> IO () repeatN 0 a = return () repeatN n a = do { a; repeatN (n-1) a } Main > repeatN 10 (putChar ‘x’)
53
(S)DT 2012-2013 53 Lui en I/O … vergelijk f = let x = (error) in 3 g = do x <- getnchars (error) [] return 3 Main> f 3 Main> g Program error: error
54
(S)DT 2012-2013 54 N-queens interactief qs :: IO () qs = do i <- readi schrijf (queens i) schrijf :: Show a => [a] -> IO () schrijf [] = return () schrijf (x : xs) = do putStr “\n” c <- putStr (show x) schrijf xs -- Main> :t show -- show :: Show a => a -> String -- Main> :t () trivial type -- () :: ()
55
(S)DT 2012-2013 55 readi :: IO Int readi = riacc 0 riacc :: Int -> IO Int riacc acc = do x <- getChar if ( (tr x) < 0) then return acc else do z <- (riacc ((10* acc) + (tr x))) return z tr ‘0’ = 0 … tr ‘9’ = 9 tr _ = -1
56
(S)DT 2012-2013 56 Main> qs 4 [3,1,4,2] [2,4,1,3] Main> qs 6 [5,3,1,6,4,2] [4,1,5,2,6,3] [3,6,2,5,1,4] [2,4,6,1,3,5]
57
Doing “timings” import CPUTime main :: IO Int main = do t1 <- getCPUTime let f1 = fib(21) print f1 -- forceert de oproep van fib t2 <- getCPUTime print "uitvoeringstijd : " print (t2-t1) -- in picoseconden (10 -12) return f1 {- oproep 17711 Main> do { a<- main; print a } "uitvoeringstijd : " -} 140625000000 17711 (S)DT 2012-2013 57
58
(S)DT 2012-2013 58 De klasse Show data Itree = Leeg | Node Itree Int Itree instance Show Itree where -- showsPrec :: Int -> a -> (String -> String) showsPrec n Leeg = ([]++) showsPrec n (Node t1 i t2) = let n1 = n+1 ni = n+i in (showsPrec n1 t1).((show ni)++).(showsPrec n1 t2) -- show x = showsPrec 0 x “” Main> show (Node (Node Leeg 23 Leeg) 5 Leeg) “245”
59
(S)DT 2012-2013 59 In feite: I/O Monad Haskell maakt gebruik van monads om berekeningen met waarden te structureren: bijvoorbeeld te sequentialiseren. I/O is in feite ook zo’n monad en de do- syntax kan gebruikt worden voor monads. Nog een monad: berekening die kan falen data Maybe a = Nothing | Just a In Prelude class Monad m where …
60
(S)DT 2012-2013 60 Haskell: einde deel 2
Verwante presentaties
© 2024 SlidePlayer.nl Inc.
All rights reserved.