Algebraische Datentypen ALP I Funktionale Programmierung Wiederholung SS 2013 Prof. Dr. Margarita Esponda ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Funktionale Programmierung Was haben wir bis jetzt gemacht? Prof. Dr. Margarita Esponda ✴ Ausdrücke und Primitive Datentypen ✴ Funktionsdefinitionen ✴ Listen und Standardfunktionen für Listen ✴ List-Sequenzen, Listengeneratoren ✴ Tupel, Zeichenketten ✴ Einfache Rekursion und Endrekursion ✴ Such- und Sortieralgorithmen ✴ Funktionen höherer Ordnung ✴ Polymorphe Funktionen ✴ Algebraische und abstrakte Datentypen ✴ Haskell-Typsystem Funktionale Programmierung Was haben wir bis jetzt gemacht? ✴ Listen und Standardfunktionen für Listen (:, ++, !!, length, take, drop, zip) ✴ List-Sequenzen, Listengeneratoren Man muss Syntax und Semantik beherrschen ✴ Tupel, Zeichenketten (fst, snd, curry, uncurry) ✴ Einfache Rekursion und Endrekursion Rekursion → Endrekursion Prof. Dr. Margarita Esponda Funktionale Programmierung Was haben wir bis jetzt gemacht? ✴ Such- und Sortieralgorithmen Komplexitätsanalyse von Funktionen ✴ Funktionen höherer Ordnung Faltungsoperatoren als Abstraktionspattern bestimmter Art von rekursiver Funktionen. (foldr, foldl, map, filter, Funktionskomposition) ✴ Polymorphe Funktionen und Polymorphe Funktionen mit einem Klassenkontext. ✴ Algebraische und abstrakte Datentypen nicht rekursive und rekursive (Zahlen, Bäume) ✴ Haskell-Typsystem Prof. Dr. Margarita Esponda Wiederholungsbeispiel Implementierung der Huffman-Kodierung in Haskell (aus dem Buch von S. Thompson) 7 Module HTypes.hs Definition der Datentypen Frequency.hs Berechnung der Häufigkeiten MakeTree.hs MakeCode.hs Erzeugung des H-Baums CodeTable.hs Tabelle für die Kodierung Coding.hs Definition der Hauptfunktionen Main.hs Zum Testen ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 HTypes.hs Hier werden alle Datentypen definiert und exportiert Huffman-Baum module HTypes ( HTree (Leaf, Node), für die Bitdarstellung Bit (L, R), HCode, Datentyp der Endkodierung HTable ) where Tabelle, die aus dem Huffman-Baum erstellt wird. data Bit = L | R deriving (Eq, Show) type HCode = [Bit] type HTable = [ (Char, HCode) ] data HTree = Leaf Char Int | Node Int HTree HTree deriving (Show) ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 HTypes.hs data HTree = Leaf Char Int | Node Int HTree HTree deriving (Show) data Bit = L | R deriving (Eq, Show) L type HCode = [Bit] type HTable = [ (Char, HCode) ] [ ( 'T', ( 'W', ( 'A', ( 'N', ( 'R', ( 'D', ] [L,L] ), [L,R,L] ), [L,R,R] ), [R,L] ), [R,R,L ), [R,R,R] ) ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 24 R 10 14 L R L R N T 4 6 6 L R 8 L R W A R D 3 3 4 4 Frequency.hs Allgemeine mergeSort-Funktion, die eine mergeFunktion als Argument bekommt. module Frequency (frequency) -- [Char] -> [(Char,Int)] where mergeSort :: ([a]->[a]->[a])-> [a] -> [a] mergeSort merge xs | (length xs < 2) = xs | otherwise = merge (mergeSort merge first) (mergeSort merge second) where first = take half xs second = drop half xs half = (length xs) `div`2 ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Frequency.hs module Frequency (frequency) where … alphaMerge :: [(Char, Int)] -> [(Char,Int)] -> [(Char,Int)] alphaMerge xs [] = xs alphaMerge [] ys = ys alphaMerge ((p,n):xs) ((q,m):ys) | (p==q) | (p<q) = (p,n+m) : alphaMerge xs ys = (p,n) : alphaMerge xs ((q,m):ys) | otherwise = (q,m) : alphaMerge ((p,n):xs) ys Wenn zwei Tupel die gleichen Zeichen haben, werden sie verschmelzt. ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Frequency.hs module Frequency (frequency) where ... freqMerge :: [(Char, Int)] -> [(Char,Int)] -> [(Char,Int)] freqMerge xs [] = xs freqMerge [] ys = ys freqMerge ((p,n):xs) ((q,m):ys) | (n<m || (n==m && p<q)) = (p,n) : freqMerge xs ((q,m):ys) | otherwise = (q,m) : freqMerge ((p,n):xs) ys Die Tupels werden nach Häufigkeit sortiert. Wenn die Häufigkeit gleich ist, dann werden die Tupels nach den Zeichen sortiert. ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Frequency.hs module Frequency (frequency) -- [Char] -> [(Char,Int)] where ... frequency :: [Char] -> [(Char, Int)] frequency = mergeSort freqMerge . mergeSort alphaMerge . map start where start ch = (ch,1) frequency "WELCHE BUCHSTABEN WERDEN ..." ⇒ [('A',1),('D',1),('L',1),('R',1),('S',1),('T',1),('U',1),('B',2),('C',2),('H',2), ('N',2),('W',2),(' ',3),('.',3),('E',5)] ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Frequency.hs frequency :: [Char] -> [(Char, Int)] frequency = mergeSort freqMerge . mergeSort alphaMerge . map start where start ch = (ch,1) frequency "WELCHE WELCHE ..." ⇒ (mergeSort freqMerge . mergeSort alphaMerge . map start) "WELCHE WELCHE ..." ⇒ mergeSort freqMerge (mergeSort alphaMerge (map start "WELCHE WELCHE ...")) ⇒ mergeSort freqMerge (mergeSort alphaMerge [('W',1),('E',1),('L',1)('C',1), ...]) ⇒ mergeSort freqMerge [(' ',2),('.',3),('C',2),('E',4),('H',2),('L',2),('W',2)] ⇒ [(' ',2),('C',2),('H',2),('L',2),('W',2),('.',3),('E',4)] ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 MakeTree.hs -- Prelude curry :: ((a, b) -> c) -> a -> b -> c -- curry converts an uncurried function to a curried function. uncurry :: (a -> b -> c) -> (a, b) -> c -- uncurry converts a curried function to a function on pairs. f = curry g g = uncurry f ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 MakeTree.hs module MakeTree ( makeTree, toTreeList ) where import HTypes ( HTree ( Leaf, Node ), Bit ( L, R ), HCode, HTable ) makeTree :: [(Char, Int)] -> HTree makeTree = makeCodes . toTreeList toTreeList :: [(Char, Int)] -> [HTree] toTreeList = map (uncurry Leaf) toTreeList [(' ',2),('C',2),('H',2),('L',2),('W',2),('.',3),('E',4)] ⇒ [Leaf ' ' 2, Leaf 'C' 2, Leaf 'H' 2, Leaf 'L' 2, Leaf 'W' 2, Leaf '.' 3, Leaf 'E' 4] ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Funktionale Programmierung Erzeugung des Huffman-Baumes [ L P V ? M B U I W A S C H R D T N _ E 1 1 1 1 2 2 2 2 3 3 4 4 4 4 4 4 6 9 14 ] [Leaf 'L' 1, Leaf 'p' 1, Leaf 'V' 1, Leaf '?' 1, Leaf 'M' 2, Leaf '.' 3, Leaf 'E' 4, . . . ] data HTree = Leaf Char Int | Node Int HTree HTree deriving (Show) Prof. Dr. Margarita Esponda MakeTree.hs module MakeTree ( makeTree, toTreeList ) where import HTypes ( HTree ( Leaf, Node ), Bit ( L, R ), HCode, HTable ) makeTree :: [(Char, Int)] -> HTree makeTree = makeCodes . toTreeList toTreeList :: [(Char, Int)] -> [HTree] toTreeList = map (uncurry Leaf) amalgamate :: [HTree] -> [HTree] amalgamate (t1:t2:ts) = insertTree (join t1 t2) ts makeCodes :: [HTree] -> HTree makeCodes [t] = t makeCodes ts = makeCodes (amalgamate ts) ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Funktionale Programmierung Erzeugung des Huffman-Baumes L P V ? M B U I W A S C H R D T N _ E 1 1 1 1 2 2 2 2 3 3 4 4 4 4 4 4 6 9 14 1. Die zwei Knoten mit den kleinsten Häufigkeiten in der Liste werden extrahiert und deren Häufigkeiten addiert. Amalgamate 2. Die Summe wird in einem neu erzeugten Knoten gespeichert, der als linkes und rechtes Kind die zwei extrahierten Knoten hat. join V ? M B U I W A S C H R D T N _ E 1 1 2 2 2 2 3 3 4 4 4 4 4 4 6 9 14 2 L P 1 1 Prof. Dr. Margarita Esponda Funktionale Programmierung Erzeugung des Huffman-Baumes V ? 1 1 2 L P 1 1 M B U I W A S C H R D T N _ E 2 2 2 2 3 3 4 4 4 4 4 4 6 9 14 insertTree 3. Zum Schluss wird die Wurzel des neuen Binärbaums wieder in die Liste eingefügt. Prof. Dr. Margarita Esponda MakeTree.hs ... join :: HTree -> HTree -> HTree join t1 t2 = Node (freq1+freq2) t1 t2 where freq1 = value t1 freq2 = value t2 value :: HTree -> Int value (Leaf _ n ) = n value (Node n _ _) = n insertTree :: HTree -> [HTree] -> [HTree] insertTree t [] = [t] insertTree t (t1:ts) | value t < value t1 = t:t1:ts | otherwise = t1 : insertTree t ts ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Funktionale Programmierung Erzeugung des Huffman-Baumes 2 2 V ? 1 1 L P 1 1 M B U I W A S C H R D T N _ E 2 2 2 2 3 3 4 4 4 4 4 4 6 9 14 makeCodes :: [HTree] -> HTree makeCodes [t] = t makeCodes ts = makeCodes (amalgamate ts) amalgamate :: [HTree] -> [HTree] amalgamate (t1:t2:ts) = insertTree (join t1 t2) ts Prof. Dr. Margarita Esponda Erzeugung des Huffman-Baumes 2 2 V ? L P 1 1 1 1 M B U I W A S C H R D T N _ E 2 2 2 2 3 3 4 4 4 4 4 4 6 9 14 makeCodes :: [HTree] -> HTree makeCodes [t] = t makeCodes ts = makeCodes (amalgamate ts) amalgamate :: [HTree] -> [HTree] amalgamate (t1:t2:ts) = insertTree (join t1 t2) ts Prof. Dr. Margarita Esponda Erzeugung des Huffman-Baumes M B U I W A S C H R D T N _ E 2 2 2 2 3 3 4 4 4 4 4 4 6 9 14 4 2 2 V ? L P 1 1 1 1 makeCodes :: [HTree] -> HTree makeCodes [t] = t makeCodes ts = makeCodes (amalgamate ts) amalgamate :: [HTree] -> [HTree] amalgamate (t1:t2:ts) = insertTree (join t1 t2) ts Prof. Dr. Margarita Esponda Erzeugung des Huffman-Baumes M B U I W A 2 2 2 2 3 3 4 2 S C H R D T N _ E 4 4 4 4 4 4 6 9 14 2 V ? L P 1 1 1 1 makeCodes :: [HTree] -> HTree makeCodes [t] = t makeCodes ts = makeCodes (amalgamate ts) amalgamate :: [HTree] -> [HTree] amalgamate (t1:t2:ts) = insertTree (join t1 t2) ts Prof. Dr. Margarita Esponda Erzeugung des Huffman-Baumes U I W A 2 2 3 3 4 S C H R D T N _ E 4 4 4 4 4 4 6 9 14 4 2 M B 2 2 2 V ? L P 1 1 1 1 makeCodes :: [HTree] -> HTree makeCodes [t] = t makeCodes ts = makeCodes (amalgamate ts) amalgamate :: [HTree] -> [HTree] amalgamate (t1:t2:ts) = insertTree (join t1 t2) ts Prof. Dr. Margarita Esponda Erzeugung des Huffman-Baumes U I W A 2 2 3 3 4 4 M B 2 2 2 S C H R D T N _ E 4 4 4 4 4 4 6 9 14 2 V ? L P 1 1 1 1 makeCodes :: [HTree] -> HTree makeCodes [t] = t makeCodes ts = makeCodes (amalgamate ts) amalgamate :: [HTree] -> [HTree] amalgamate (t1:t2:ts) = insertTree (join t1 t2) ts Prof. Dr. Margarita Esponda Erzeugung des Huffman-Baumes [ ] 41 30 E 16 14 24 17 _ 8 C H 4 4 4 V ? L P 1 1 1 1 14 N T 4 2 10 9 S 2 Prof. Dr. Margarita Esponda 8 8 4 6 4 4 6 8 U I M B W A R D 2 2 2 2 3 3 4 4 Erzeugung des Huffman-Baumes [ ] 71 41 30 E 16 14 24 17 _ 8 8 8 makeCodes :: [HTree] -> HTree C H S 2 V ? L P 1 1 1 1 14 N T makeCodes [t] = t 4 4 4 4 4 ts)4 makeCodes ts = makeCodes (amalgamate 2 10 9 6 4 6 8 U I M B W A R D 2 2 2 2 3 3 4 4 Erzeugung des Huffman-Baumes 71 41 30 E 16 14 24 17 _ 8 C H 4 4 8 8 S 4 2 V ? L P 1 1 1 1 14 N T 4 2 10 9 4 6 4 4 6 8 U I M B W A R D 2 2 2 2 3 3 4 4 Coding.hs module CodeTable ( codeTable ) where import HTypes codeTable :: HTree -> HTable codeTable = convert [] where convert :: HCode -> HTree -> HTable convert hc (Leaf c n) = [(c, hc)] convert hc (Node n tl tr) = (convert (hc++[L]) tl) ++ (convert (hc++[R]) tr) ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Kodierung der Zeichen codeTable Der Code jedes 71 L convert Zeichens wird aus dem Weg von der Wurzel des Baumes 30 bis zu dem convert L R convert entsprechenden E Buchstaben aus 16 14 den Kanten convert L R convert abgelesen. L 8 17 L H 4 4 R convert 24 convert L R 8 R L S 4 convert R 10 9 R R L convert 14 L 4 R 2 L RL R V ? L P 1 1 1 1 L RL U I M 2 2 2 convert 6 4 4 R N T 4 2 41 _ R L L Prof. Dr. Margarita Esponda convert L 8 C convert R convert 6 8 L R L R B W A R D 2 3 3 4 4 R convert convert Coding.hs module CodeTable ( codeTable ) where import HTypes codeTable :: HTree -> HTable codeTable = convert [] where convert :: HCode -> HTree -> HTable convert hc (Leaf c n) = [(c, hc)] convert hc (Node n tl tr) = (convert (hc ++ [L]) tl) ++ (convert (hc ++ [R]) tr) ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Kodierung der Zeichen Der Code jedes Zeichens wird aus dem Weg von der Wurzel des Baumes bis zu dem entsprechenden L Buchstaben aus den E Kanten abgelesen. 14 [ ('E', [L, L]), ('_', [L, R, L]), ('C ', [L, R, L, L]), . L codeTable 71 L 30 L R L 16 L R L H 4 4 . L S 4 R 10 9 R 14 R L L 4 R 2 ('P', [L,R,R,L,R,R]) L RL R ] V ? L P 1 1 1 1 L RL U I M 2 2 2 6 4 4 R N T 4 2 24 L R 8 R L R _ 8 C 41 17 R 8 . Prof. Dr. Margarita Esponda R 6 8 L R L R B W A R D 2 3 3 4 4 R Coding.hs Hauptfunktionen für die Codierung und Decodierung von Nachrichten. module Coding ( code, decode ) where import HTypes ( HTree ( Leaf, Node ), Bit ( L, R ), HCode, HTable ) code :: HTable -> [Char] -> HCode code htable = concat . map (lookup htable) lookup :: HTable -> Char -> HCode lookup [] c = error "lookup..." lookup ((char, hc):rtable) c | char == c | otherwise ... ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 = hc = lookup rtable c Dekodierung 0010110010111010111100101 E 71 0 1 30 0 0 1 41 1 E 14 16 0 24 17 1 0 0 1 1 _ 0 8 8 1 C H 4 4 0 0 S 4 1 2 0 2 1 0 1 V ? L P 1 1 1 1 Prof. Dr. Margarita Esponda 10 9 1 14 1 0 4 1 0 N 6 4 1 1 0 T 4 4 0 0 8 1 6 8 0 1 0 1 U I M B W A R D 2 2 2 2 3 3 4 4 Coding.hs Hauptfunktionen für die Codierung und Decodierung von Nachrichten. module Coding ( code, decode ) ... decode :: HTree -> HCode -> [Char] decode htree = decodeByte htree where decodeByte (Node n t1 t2) (L:rest) = decodeByte t1 rest decodeByte (Node n t1 t2) (R:rest) = decodeByte t2 rest decodeByte (Leaf c n) rest = c:decodeByte htree rest decodeByte t [] = [] ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Dekodierung 0010110010111010111100101 E 71 0 1 30 0 _ 0 1 41 1 E 14 16 0 24 17 1 0 0 1 1 _ 0 8 8 1 C H 4 4 0 0 S 4 1 2 0 2 1 0 1 V ? L P 1 1 1 1 Prof. Dr. Margarita Esponda 10 9 1 14 1 0 4 1 0 N 6 4 1 1 0 T 4 4 0 0 8 1 6 8 0 1 0 1 U I M B W A R D 2 2 2 2 3 3 4 4 Dekodierung 0010110010111010111100101 E 71 0 M 1 30 0 _ 0 1 41 1 E 14 16 0 24 17 1 0 0 1 1 _ 0 8 8 1 C H 4 4 0 0 S 4 1 2 0 2 1 0 1 V ? L P 1 1 1 1 Prof. Dr. Margarita Esponda 10 9 1 14 1 0 4 1 0 N 6 4 1 1 0 T 4 4 0 0 8 1 6 8 0 1 0 1 U I M B W A R D 2 2 2 2 3 3 4 4 Dekodierung 0010110010111010111100101 _ E _ M N H N 71 0 Damit die Information später dekodiert werden kann, muss 1 30 0 0 1 der dazu gehörige Huffman- 41 Baum in der komprimierten Datei beinhaltet sein. 1 E 14 16 0 24 17 1 0 0 1 1 _ 0 8 8 1 C H 4 4 0 0 S 4 1 2 0 2 1 0 1 V ? L P 1 1 1 1 Prof. Dr. Margarita Esponda 10 9 1 14 1 0 4 1 0 N 6 4 1 1 0 T 4 4 0 0 8 1 6 8 0 1 0 1 U I M B W A R D 2 2 2 2 3 3 4 4 MakeCode.hs module MakeCode ( codes, codeTable ) where import HTypes ( HTree ( Leaf, Node ), Bit ( L, R ), HCode, HTable ) import Frequency ( frequency ) import MakeTree ( makeTree ) import CodeTable ( codeTable ) codes :: [Char] -> HTree Hier werden die Häufigkeiten und der Huffman-Baum erzeugt. codes = makeTree . frequency codes "WELCHE WELCHE …" ⇒ Node 17 (Node 8 (Leaf 'E' 4) (Node 4 (Leaf ' ' 2) (Leaf 'C' 2))) (Node 9 (Node 4 (Leaf 'H' 2) (Leaf 'L' 2)) (Node 5 (Leaf 'W' 2) (Leaf '.' 3))) ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Main.hs module Main where import HTypes ( Tree(Leaf,Node), Bit(L,R), HCode, HTable ) import Coding ( code, decode ) import MakeCode ( codes, codeTable ) import Frequency ( frequency ) import MakeTree( makeTree, toTreeList ) ... Alle Module werden hier importiert, um die einzelnen Funktionen testen zu können. code htree "WELCHE WELCHE ..." ⇒ [R,R,L,L,L,R,L,R,L,R,R,R,L,L,L,L,L,R,L,R,R,L,L,L,R,L,R,L,R,R,R,L,L,L,L,L,R,L, R,R,R,R,R,R,R,R,R] ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Main.hs module Main where import HTypes ( Tree(Leaf,Node), Bit(L,R), HCode, HTable ) import Coding ( code, decode ) import MakeCode ( codes, codeTable ) import Frequency ( frequency ) import MakeTree( makeTree, toTreeList ) ... decode Alle Module werden hier importiert, um die einzelnen Funktionen testen zu können. htree [R,R,L,L,L,R,L,R,L,R,R,R,L,L,L,L,L,R,L,R,R,L,L,L,R,L,R,L, R,R,R,L,L,L,L,L,R,L,R,R,R,R,R,R,R,R,R] ⇒ "WELCHE WELCHE ..." ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 Funktionale Programmierung Lokale Variablennamen Es gibt in Haskell eine zweite Möglichkeit, lokale Variablen zu definieren mit Hilfe des let-in-Ausdrucks. Allgemeine Form: let Lokale Definitionen in Beispiel: f x y = let Ausdruck a = x+y*2 b = x-y/2 in (a+b*b) f x y = Prof. Dr. Margarita Esponda x + y*2 + (x-y/2)*(x-y/2) Funktionale Programmierung Lokale Variablennamen Beispiele: u = let a = 2 b = a + ( let a = 3 b=c in a+b ) c = a^2 in b*b u n = let a = 2*n b = a + ( let a = 3 b=c in a+b ) c = a^2 in b*b Prof. Dr. Margarita Esponda Algebraische Datentypen Wichtige Hinweise für die Zwischenklausur: 1) Schreiben Sie in allen Funktionen die entsprechende Signatur. 2) Verwenden Sie die vorgegebenen Funktionsnamen, falls diese angegeben werden. 3) Die Zwischenklausur muss geheftet bleiben. 4) Schreiben Sie Ihre Antworte in den dafür vorgegebenen freien Platz, der unmittelbar nach der Frage steht. ALP I: Margarita Esponda, 17. Vorlesung, 02.12.2012 44