Funktionale Programmierung ALP I Algebraische Datentypen und Abstrakte Datentypen SS 2013 Prof. Dr. Margarita Esponda Prof. Dr. Margarita Esponda Abstrakt Datentypen Algebraischen Datentypen für Bäume Beispiel: data SBTree = L | N SBTree SBTree N N N L L ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 L N L L Abstrakt Datentypen Einfache binäre Bäume data SBTree = L | N SBTree SBTree deriving Show Ein balancierter Baum type Depth = Integer mit der eingegebenen genSBTree :: Depth -> SBTree Tiefe wird erstellt. genSBTree 0 = L genSBTree (n+1) = N (genSBTree n) (genSBTree n) N N N genSBTree 3 ⇒ N L ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 L N L N N L L L L L Abstrakt Datentypen Berechnung aller Knoten des Baumes nodes :: SBTree -> Integer nodes L = 1 nodes (N leftT rightT) = 1 + nodes leftT + nodes rightT nodes (genSBTree 3) N ⇒ 15 N N N L ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 L N L N N L L L L L Abstrakt Datentypen Tiefe des Baumes depth :: SBTree -> Integer depth L = 0 depth (N lt rt) = (max (depth lt) (depth rt)) + 1 N depth N (N (N L L) L) (N L L) ⇒ 3 N L ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 N N L L L L Abstrakt Datentypen joinTrees :: SBTree -> SBTree -> SBTree joinTrees leftTree rightTree = N leftTree rightTree joinTrees leftT rightT ⇒ N leftT rightT N leftT L rightT N N L L ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 N N N L L rightT leftT L N L L L L Abstrakt Datentypen balanced :: SBTree -> Bool balanced L = True balanced (N lt rt) = (balanced lt) && (balanced rt) && depth lt == depth rt balanciert N L L N L N N N N nicht balanciert balanciert L ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 N N L L L N L L L L L Abstrakt Datentypen Algebraischer Datentyp für Binäre Suchbäume Beispiel: data Tree = Leaf Int | Node Int Tree Tree | Nil 53 ist sortiert. 69 27 13 Die gespeicherte Information 34 63 46 ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 95 Algebraische Datentypen für Binäre Suchbäume Operationen für Binäre Suchbäume data BSTree a = Nil | Node a (BSTree a) (BSTree a) deriving ( Show, Eq ) -- findet das kleinste Element smallest:: (Ord a) => BSTree a -> a smallest (Node x Nil _) = x smallest (Node x leftTree _) = smallest leftTree 53 69 27 13 34 63 46 Prof. Dr. Margarita Esponda 95 Algebraische Datentypen für Binäre Suchbäume Algebraischer Datentyp für Binäre Suchbäume data BSTree a = Nil | Node a (BSTree a) (BSTree a) deriving ( Show, Eq ) -- findet das größte Element biggest:: (Ord a) => BSTree a -> a biggest(Node x _ Nil) = x biggest(Node x _ rightTree) = biggest rightTree -- spiegelt einen Baum mirror:: (Ord a) => BSTree a -> BSTree a mirror Nil = Nil mirror (Node x xl xr) = Node x (mirror xr) (mirror xl) Prof. Dr. Margarita Esponda Algebraische Datentypen für Binäre Suchbäume Traversierung binärer Bäume Baumtraversierung bedeutet, alle Knoten des Baumes in einer bestimmten Reihenfolge zu besuchen. Preorder: Wurzel – linker Unterbaum – rechter Unterbaum Inorder: linker Unterbaum - Wurzel – rechter Unterbaum Postorder: linker Unterbaum – rechter Unterbaum - Wurzel Levelorder: von oben nach unten in jeder Ebene von links nach rechts ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 23 Traversierung binärer Bäume Inorder Linker Unterbaum - Wurzel - Rechter Unterbaum F D B A I E C A B C D E F G H I J ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 J G H Algebraische Datentypen für Binäre Suchbäume Traversierung von Binärbäumen -- verwandelt einen sortierten Baum in eine sortierte Liste inOrder :: (Ord a) => BSTree a -> [a] inOrder Nil = [] inOrder (Node x ltree rtree) = inOrder ltree ++ x : inOrder rtree Prof. Dr. Margarita Esponda Algebraische Datentypen -- verwandelt einen Baum in eine Liste preOrder :: (Ord a) => BSTree a -> [a] preOrder Nil = [] preOrder (Node x ltree rtree) = x : preOrder ltree ++ preOrder rtree F D B A I E C F D B A C E I G H J Prof. Dr. Margarita Esponda J G H Binärbäume Binärbäume einfachste Beispiele: AVL-Bäume Baumstrukturen Red-Black-Bäume ausgeglichene Bäume B-Bäume usw. Die wichtigste Voraussetzung für die effiziente Verwaltung von Datenmengen mit Hilfe von Bäumen ist, dass die Bäume balanciert sind. ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 Algebraische Datentypen Suchen 3 11 19 7 3 1 Nil 11 9 3 3 16 5 Nil Nil Nil 15 Nil Nil 19 7 1 Nil Nil 9 16 5 Nil Nil Nil 15 Nil Nil Nil search :: (Ord a) => a -> BSTree a -> Bool search _ Nil = False search k (Node x ltree rtree) | k==x = True | k<x = search k ltree | otherwise = search k rtree Prof. Dr. Margarita Esponda Algebraische Datentypen 6 11 19 7 3 1 Nil Nil Einfügen 9 5 Nil Nil Nil 15 Nil 11 23 16 Nil Nil 19 7 Nil 3 Nil 1 Nil Nil 9 5 Nil Nil 15 Nil 6 Nil Nil Prof. Dr. Margarita Esponda 23 16 Nil Nil Nil Nil Algebraische Datentypen Einfügen insert :: (Ord a) => a -> BSTree a -> BSTree a insert a Nil = Node a Nil Nil insert a (Node x ltree rtree) | a<x = Node x (insert a ltree) rtree | otherwise = Node x ltree (insert a rtree) Prof. Dr. Margarita Esponda Algebraische Datentypen Minimum und Maximum 53 Minimum 27 13 Maximum 69 34 63 95 Der erste Knoten, der keine linken Kinder mehr hat, beinhaltet das kleinste Element. -- findet das kleinste Element 17 46 smallest (Node x Nil _) = x smallest (Node x leftTree _) = smallest leftTree -- findet das größte Element biggest(Node x _ Nil) = x biggest(Node x _ rightTree) = biggest rightTree Prof. Dr. Margarita Esponda Algebraische Datentypen Löschen mit "Brute force" list2Tree [] = Nil list2Tree (x:xs) = insert x (list2Tree xs) remove _ [] = [] remove y (x:xs) | y==x = xs | otherwise = x:(remove y xs) delete a Nil = Nil delete a tree = list2Tree(remove a (preOrder tree)) Prof. Dr. Margarita Esponda Algebraische Datentypen Nachfolger 1. Fall 53 Es gibt einen rechten Unterbaum. Minimum 13 8 69 30 34 63 17 46 39 Prof. Dr. Margarita Esponda 95 Algebraische Datentypen Nachfolger 2. Fall 53 Es gibt keinen rechten Unterbaum. 13 8 69 30 34 63 17 46 95 Maximum 39 Wie können wir nach oben laufen? Prof. Dr. Margarita Esponda Algebraische Datentypen Delete-Operation ( Löschen ) 1. Fall 2. Fall Löschen eines Knotens ohne Kinder Löschen eines Knotens mit nur einem Kind 53 53 27 13 69 34 17 Prof. Dr. Margarita Esponda 63 46 27 Nil 95 13 69 34 63 46 95 Algebraische Datentypen Löschen Löschen eines Knotens mit zwei Kindern 3. Fall Der Knoten, den man löschen möchte, wird durch seinen Nachfolger ersetzt. 53 53 27 13 8 17 69 34 30 63 46 69 30 13 95 8 17 34 32 63 95 46 32 Der Nachfolger von 27 ist das Minimum des rechten Unterbaumes. Das Minimum ist entweder ein Blatt oder hat maximal ein rechtes Kind. Prof. Dr. Margarita Esponda Algebraische Datentypen Löschen Löschen eines Knotens mit zwei Kindern Wir brauchen eine join-Funktion, die aus zwei KinderBäumen einen baut. 53 53 27 69 join 34 13 63 95 34 13 8 17 30 69 46 8 17 30 46 32 32 Prof. Dr. Margarita Esponda 63 95 Algebraische Datentypen Löschen etwas besser delete :: (Ord a) => a-> BSTree a-> BSTree a delete x Nil = Nil delete x (Node y ltree rtree) | x < y = Node y (delete x ltree) rtree | x == y = join ltree rtree | x > y = Node y ltree (delete x rtree) …… Prof. Dr. Margarita Esponda Algebraische Datentypen Join-Funktion join :: (Ord a) => BSTree a-> BSTree a-> BSTree a join xtree Nil = xtree join xtree ytree = Node e xtree ntree where (e, ntree) = splitMin ytree -- splitMin :: BSTree a -> (a, BSTree a) splitMin (Node x Nil tree) = (x, tree) splitMin (Node x ltree rtree) = (f, Node x ntree rtree) where (f, ntree) = splitMin ltree Prof. Dr. Margarita Esponda Algebraische Datentypen Probleme mit einfachen binären Suchbäumen balancierter Binärbaum nicht balancierter Binärbaum 53 53 27 13 69 34 17 30 63 46 83 30 95 95 59 139 71 65 60 62 Prof. Dr. Margarita Esponda 77 Algebraische Datentypen Algebraische Datentypen -- für arithmetische Ausdrücke data Expr = Lit Int | Add Expr Expr | Sub Expr Expr | Mult Expr Expr eval :: Expr -> Int eval (Lit n) = n eval (Add x y) = eval x + eval y eval (Sub x y) = eval x - eval y eval (Mult x y) = eval x * eval y eval (Mult (Add (Lit 3) (Lit 4)) (Lit 3)) Prof. Dr. Margarita Esponda => 21 Funktionale Programmierung Haskell Typsystem Monomorphe Funktionen Der Datentyp wird genau durch die Signatur bestimmt Beispiel: asciiCode :: Char -> Int Polymorphe Funktionen Typvariablen in der Signatur lassen beliebige Datentypen zu Beispiel: length :: [a] -> [a] Prof. Dr. Margarita Esponda Funktionale Programmierung Einschränkung von Typen Mit Hilfe von vordefinierten Typ-Klassen können polymorphe Funktionen mit Einschränkung definiert werden Verwendung eines Kontextes Beispiel: equalList :: Eq a => [a]->[a]->Bool nur für Datentypen mit Gleichheitsoperator add2List:: Num a => [a] -> a -> [a] add2List xs y = map (+y) xs nur numerische Typen mit definierten arithmetischen Operationen Prof. Dr. Margarita Esponda Funktionale Programmierung Einige vordefinierte Typ-Klassen Klassenname Show, Read Eigenschaften anzeigbar oder lesbar (a → String), (String → a) Funktionen show, read Eq vergleichbar (==), (/=) Ord sortierbar compare, (<), (>), (<=), (>=), min, max, .. Enum aufzählbar succ, pred, [..] Num allgemeine Zahlen (+), (-), (*), negate, abs Integral ganzzahlig mod, div, quot, rem Fractional Kehrwert-Funktion (/), recip,... Prof. Dr. Margarita Esponda Funktionale Programmierung Typ-Anpassung In Haskell ist Typ-Anpassung für numerische Werte wie in anderen Programmiersprachen nicht erlaubt. Beispiel: mod 3 2 + 1.5 Fehler: <interactive>:1:10: Ambiguous type variable `t' in the constraints: `Fractional t' arising from the literal `1.5' at <interactive>:1:10-12 `Integral t' arising from a use of `mod' at <interactive>:1:0-6 Probable fix: add a type signature that fixes these type variable(s) Explizites Type-Casting muss stattfinden fromIntegral (mod 3 2) + 1.5 Prof. Dr. Margarita Esponda Funktionale Programmierung Typ-Klassen Typen werden durch die Operationen, die auf ihren Werten definiert werden sollen, beschrieben. Class Num a where (+) :: a -> a -> a (*) :: a -> a -> a Typklassen sind abstrakte (-) :: a -> a -> a Schnittstellen, weil keine ... Implementierung vorgegeben wird. Prof. Dr. Margarita Esponda Funktionale Programmierung Instanzen von Typ-Klassen Mit einer Instanz-Deklaration definieren wir, welche Typen zu welchen Typ-Klassen gehören. Vordefinierte primitive Funktionen instance Num Int where x+y = primAdd x y neg x = primNegateInt x ... instance Eq Char where x == y = ord x == ord y Prof. Dr. Margarita Esponda Funktionale Programmierung Instanzen von Typ-Klassen Der Instanz-Typ einer Klasse muss die vorgeschriebenen Operationen einer Typ-Klasse implementieren. Implementierung: instance (Eq a) => Eq [a] where (==) [] [] = True (==) [] (x:xs) = False (==) (x:ys) [] = False (==) (x:xs) (y:ys) = x == y && xs == ys Prof. Dr. Margarita Esponda Funktionale Programmierung Instanzen von Typ-Klassen data Menge a = Menge [a] instance (Eq a) => Eq (Menge a) where Menge xs == Menge ys = subset xs ys && subset ys xs subset :: Eq a => a -> a -> Bool subset xs ys = all (’elem’ ys) xs instance (Ord a) => Ord (Menge a) where Menge xs <= Menge ys = subset xs ys ... Prof. Dr. Margarita Esponda Funktionale Programmierung Subklassen Klassen dürfen andere Klassen umfassen class (Eq a, Show a) => Num a where (+), (-), (*) :: a -> a -> a negate :: a -> a abs, signum :: a -> a fromInteger :: Integer -> a -- Minimal complete definition: -- All, except negate or (-) x - y = x + negate y -- Default-Definitionen negate x = 0 - x Prof. Dr. Margarita Esponda Funktionale Programmierung Mehrere Oberklassen class Enum a where class Num a where fromEnum :: a -> Int (+) :: a -> a -> a toEnum neg :: a -> a :: Int -> a ... ... class (Enum a, Num a) => Integral a where quot, rem, div, mod :: a -> a -> a quotRem, divMod even, odd :: a -> a -> (a, a) :: a -> Bool toInteger :: a -> Integer toInt :: a -> Int Prof. Dr. Margarita Esponda Integral erbt die Operationen von Enum und Num und fügt noch weitere Operationen hinzu. Ausprägungen von Integral müssen folglich auch Ausprägungen von Enum und Num sein. Funktionale Programmierung Klassenhierarchie Eq Show Num Ord Enum Real Integral Prof. Dr. Margarita Esponda Fractional Floating Algebraische Datentypen Standard Klassenhierarchie Prelude ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 53 Funktionale Programmierung Abstrakte Datentypen Konkrete Datentypen • konkrete Darstellung der Information innerhalb einer Sprache • Listen, Bäume usw. Datentypen Abstrakte Datentypen • definiert durch die Operationen unabhängig von einer konkreten Darstellung des Datentyps. Prof. Dr. Margarita Esponda Funktionale Programmierung Abstrakte Datentypen - sind Datentypen, die durch die auf ihren Werten erlaubten Operationen definiert sind und dessen Implementierung den Nutzern des Typs verborgen (Datenkapselung) ist - in Haskell werden abstrakte Datentypen mit Hilfe des Modul-Konzepts implementiert Prof. Dr. Margarita Esponda Funktionale Programmierung Module in Haskell Ein Haskell-Modul ist eine Datei mit folgender Struktur: module <Name> (<Exportliste>) where • Nur die Datentypen und Funktionen, die in <Exportliste> angegeben werden, sind nach außen sichtbar. • Wenn <Exportliste> weggelassen wird, sind alle Definitionen automatisch nach außen sichtbar. Prof. Dr. Margarita Esponda Funktionale Programmierung Module in Haskell module Stapel (Stapel, push, pop, top, createStack, isEmpty, show) where createStack :: Stapel a isEmpty :: Stapel a -> Bool push :: a-> Stapel a -> Stapel a pop :: Stapel a -> Stapel a top :: Stapel a -> a data Stapel a = Empty | S a (Stapel a) ... Prof. Dr. Margarita Esponda Funktionale Programmierung Module in Haskell module Stapel . . . ... createStack = Empty isEmpty Empty = True isEmpty _ = False push x s = S x s pop Empty = error "pop from an empty stack ..." pop (S _ s) = s top Empty = error "top from an empty stack ..." top (S x _) = x Prof. Dr. Margarita Esponda Algebraische Datentypen Abstrakte Datentyp für Mengen module Menge (Menge, emptySet, isEmpty, inSet, insertSet, list2Set, subSet, (\\), (|||), (&&&), powerSet ) where data Menge a = Menge [a] instance Eq a => Eq (Menge a) where (==) s1 s2 = subSet set1 set2 && subSet s2 s1 instance (Show a) => Show (Menge a) where ... ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 59 Algebraische Datentypen Abstrakte Datentyp für Mengen module Menge . . . . emptySet :: (Menge [Int]) isEmpty :: Eq a => Menge a -> Bool inSet :: Eq a => a -> Menge a -> Bool (|||) :: Eq a => Menge a -> Menge a -> Menge a (\\) :: Eq a => Menge a -> Menge a -> Menge a (&&&) :: Eq a => Menge a -> Menge a -> Menge a subSet :: Eq a => Menge a -> Menge a -> Bool powerSet :: Eq a => Menge a -> Menge (Menge a) ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 60 Algebraische Datentypen Abstrakte Datentyp für Mengen module Menge . . . . emptySet = Menge [] isEmpty (Menge []) = True isEmpty _ = False inSet x (Menge ys) = elem x ys ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 61 Algebraische Datentypen Abstrakte Datentyp für Mengen module Menge . . . . -- Vereinigung von zwei Mengen (|||) (Menge (x:xs)) m = insertSet x ((Menge xs) ||| m) (|||) (Menge []) m = m -- Differenzmenge (\\) (Menge xs) m = Menge [x|x<-xs, not(inSet x m)] -- Schnittmenge (&&&) (Menge xs) m = Menge [x|x<-xs, (inSet x m)] ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 62 Algebraische Datentypen Abstrakte Datentyp für Mengen module Menge . . . . subSet (Menge []) _ = True subSet _ (Menge []) = False subSet (Menge (x:xs)) m = (inSet x m) && (subSet (Menge xs) m) powerSet (Menge xs) = Menge powerMenge where powerMenge = map Menge (powerList xs) powerList :: [a] -> [[a]] powerList [] = [[]] powerList (x:xs) = (powerList xs) ++ (map (x:) (powerList xs)) ALP I: Margarita Esponda, 12. Vorlesung, 26.11.2012 63