2. Abstrakte Datentypen 2.0 Begriffe Geheimnisprinzip: (information hiding principle, Parnas 1972) Zugriffe auf Teile einer Programmeinheit, die für die „reguläre Benutzung“ nicht erforderlich sind, sollten verboten sein. Besser: Die nicht benötigten Teile sollten unsichtbar sein. Warum?? hs / fub – alp3 –ADT-1 1 Warum Datenabstraktion? Vorteile 1 Sicherheit: Objekt kann nicht in ungültige Zustände gebracht werden. 2 Komfort: Benutzer kann von Repräsentation abstrahieren; Objekt wird ausschließlich über Operationen benutzt. 3 Flexibilität: Code der Klasse kann unabhängig vom benutzenden Code entwickelt werden - und ohne Auswirkungen auf den benutzenden Code geändert werden. hs / fub – alp3 –ADT-1 2 1 Datenabstraktion Datenabstraktion: (data abstraction) Anwendung des Geheimnisprinzips auf die Darstellung von (einfachen und komplexen) Daten im Rechner: die Daten sind nicht durch Zugriff auf ihre Bestandteile, sondern ausschließlich über zugehörige Operationen manipulierbar. [ Auch „Datenkapselung“ (data encapsulation) ] hs / fub – alp3 –ADT-1 3 Abstrakte Datentypen (ADT) 2.2 Spezifikation von Abstrakten Datentypen Sichtbare Schnittstelle: Typbezeichner Signaturen der Operationen Spezifikation der Operationen Abstraktionsbarriere Implementierung unsichtbar für Klient muss Spezifikation genügen! was heißt das? Verifikation? meist viele Implementierungen möglich gleiche funktionale Eigenschaften nichtfunktionale (wie Laufzeiteffizienz ) oft drastisch unterschiedlich hs / fub – alp3 –ADT-1 4 2 Spezifikation von ADT Grundsätze Keine Annahmen über Implementierung des Typs Methodensignaturen ("Prozedurköpfe") festlegen Semantik der Methoden festlegen - Kann formal oder umgangssprachlich erfolgen - Präzise muss es sein Zwei Verfahren Algebraische Spezifikation Modellierende Spezifikation Modell zugrunde legen, Voraussetzungen, zu erzielende Effekte, Invarianten darin spezifizieren Ähnlich wie bisher: Modell war Zustandsraum, allerdings implementierungsabhängig ! Besser: Natürliche Zahlen, Mengen, Listen, .... Wichtig: Spezifizierende und Implementierer müssen gleiches Verständnis des Modells haben ("gleiche Semantik") hs / fub – alp3 –ADT-1 5 Spezifikation von ADT 2.2.1 Algebraische Spezifikation ADT wird festgelegt durch: Wertemengen (Typen, Sorten) Signaturen der Operationen --------------------------------Definierende Gleichungen Syntax Semantik legen Beziehungen zwischen Operationen fest hs / fub – alp3 –ADT-1 6 3 Stack (algebraisch) types Stack, T, Bool , Int // repräsentiert durch Typen operators createStack : -> Stack push: T -> Stack -> Stack pop : Stack -> Stack top : Stack -> T size : Stack -> Int axioms .... hs / fub – alp3 –ADT-1 7 Stack (algebraisch) axioms for all x ∈ T, s ∈ Stack : pop ( push (x , s ) ) = s top (push (x , s ) ) = x size (createStack) = 0 size (push (x , s ) ) = 1 + size (s) Einzige Möglichkeit zur Charakterisierung von Stack-Objekten sind Axiome hs / fub – alp3 –ADT-1 8 4 Stack (algebraisch) Kanonische Darstellungen Viele Darstellungen repräsentieren den gleichen Wert push( y (pop ( push (x , createStack)))) = push (y, createStack) Axiome als Ersetzungsregeln (rewrite rules) Systematische Ersetzung -> kanonische Darstellung hs / fub – alp3 –ADT-1 9 Stack (algebraisch): Haskell Signatur Stack: algebraic specification in Haskell (executable) > module Stack (Stack, createStack, push, > pop, top, size, isEmpty) > where > > > > > createStack :: Stack t push :: t -> Stack t -> Stack t pop :: Stack t -> Stack t top :: Stack t -> t size :: Stack t -> Int hs / fub – alp3 –ADT-1 10 5 Stack (algebraisch): Haskell > data Stack t = EmptyStack | NES t (Stack t) > deriving (Show) > createStack = EmptyStack > push x s = NES x s > pop > pop EmptyStack (NES x s) = error "stack underflow" = s > top > top EmptyStack (NES x s) = error "stack underflow, no top" = x > size EmptyStack > size (NES x s ) = 0 = 1 + size s > isEmpty st = size st==0 hs / fub – alp3 –ADT-1 11 Stack Anwendung: Klammergebirge Aufgabe: Prüfe, ob ein Ausdruck "richtig" geklammert ist. Beispiel: "( () ( ) (( )) )" ok "( ( ( ) (( ) ) )" nein Definition korrekter Klammerausdrücke: - eine Zeichenkette (auch leere möglich) ohne Klammern ist korrekt. - Sind S1, S2, S3 korrekt, dann auch S1 (S2) S3. - Das sind alle korrekten Klammerausdrücke. hs / fub – alp3 –ADT-1 12 6 Stack Anwendung: Klammergebirge Haskell-Programm "Korrekte Klammern" simpel application of stacks: .. > import Stack > > > > > > > > > > > > checkBrack :: String -> Bool checkBrack str = checkStack EmptyStack str checkStack :: (Stack Char) -> String -> Bool checkStack st [] | isEmpty st = True | otherwise = False checkStack st (c:rest) | c=='(' = checkStack (push '(' st) rest | c==')' = if (isEmpty st) then False else checkStack (pop st) rest | otherwise = checkStack st rest hs / fub – alp3 –ADT-1 13 7