28.12.2013 Aufrufe

Deklarative Programmierung

Deklarative Programmierung

Deklarative Programmierung

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

Was bisher geschah<br />

◮ Algebraische Datentypen<br />

◮ Typklassen und Instanzen<br />

◮ strukturelle Induktion<br />

◮ Rekursionsschemata<br />

◮ Funktionen höherer Ordnung<br />

◮ Monaden<br />

103


Wiederholung Monaden<br />

◮ Datentyp mit Grundoperationen<br />

class Monad m where<br />

return :: a -> m a<br />

( >>= ) :: m a -> (a -> m b) -> m b<br />

◮ Axiome (Monaden-Gesetze)<br />

(return x) >>= f == f x<br />

m >= return x == m<br />

( m >>= f) >>= g == m >>= (\ x -> f x >>= g)<br />

104


Beispiele<br />

◮ Listen (Nichtdeterminismus)<br />

instance Monad [] where<br />

return = \ x -> [x]<br />

m >>= f = concat ( map f m )<br />

◮ Maybe<br />

data Maybe a = Nothing | Just a<br />

instance Monad Maybe where<br />

return = \ x -> Just x<br />

m >>= f = case m of<br />

Nothing -> Nothing<br />

Just x -> f x<br />

◮ IO<br />

data World = ...<br />

data IO = World -> World<br />

data IO a = IO { World -> (a, World) }<br />

Anwendung:<br />

do cs


Übersetzer für Programme<br />

Höhere Programmiersprachen (z.B. Java, Haskell, C) erfordern<br />

Übersetzung von Quell- in Maschinen- oder Byte-Code<br />

Beispiel: Übersetzung von Java-Programmen<br />

Quellcode<br />

↓<br />

Zwischendarstellung<br />

↓<br />

Java-Bytecode<br />

Übersetzung in zwei Phasen:<br />

1. Analyse-Phase (Front-End):<br />

Transformation des Quellcodes in eine<br />

Zwischendarstellung<br />

2. Synthese-Phase (Back-End):<br />

Transformation der Zwischendarstellung in Java-Bytecode<br />

106


Analyse-Phase<br />

Quellcode Scanner −→<br />

Folge von Token Parser −→<br />

Syntaxbaum<br />

lexikalische Analyse (Scanner)<br />

lineare Analyse des Quelltextes, Aufteilung in<br />

Einheiten (Token)<br />

z.B. Schlüsselwörter, Bezeichner, Zahlen<br />

reguläre Sprachen, endliche Automaten<br />

syntaktische Analyse (Parser)<br />

hierarchische Struktur des Quelltextes<br />

z.B. Ausdrücke, Verzweigungen, Schleifen<br />

kontextfreie Sprachen, Kellerautomaten<br />

semantische Analyse Annotationen im Syntaxbaum,<br />

z.B. Typprüfungen<br />

107


Einsatz ähnlicher Methoden<br />

◮ Übersetzung von Daten zwischen verschiedenen Formaten<br />

◮ Verarbeitung von Domain-spezifischen Sprachen<br />

◮ Textformatierung<br />

◮ kontextabhängige Hilfe in Entwicklungsumgebungen<br />

◮ statische Analyse zur Fehlersuche in Programmen<br />

◮ Interpreter<br />

◮ graphische Editoren (z.B. für UML-Diagramme) mit<br />

Programmerzeugung<br />

108


Parser<br />

Eingabe:<br />

Ausgabe:<br />

Beispiele:<br />

String (Liste von Char)<br />

Syntaxbaum o.Ä.<br />

◮ arithmetische und logische Ausdrücke<br />

◮ HTML-Code im Web-Browser<br />

◮ Haskell-Code in GHC / GHCI<br />

type Parser = String -> Tree<br />

parse :: Parser<br />

i.A. nur teilweise Verarbeitung der Eingabe<br />

type Parser = String -> (Tree, String)<br />

Ergebnis:<br />

◮ Syntaxbaum o.Ä. des verarbeiteten Teiles der Eingabe<br />

◮ unverarbeiteter Teil der Eingabe<br />

109


Nichtdeterminismus<br />

Behandlung (temporär) uneindeutiger Ableitungen<br />

mehrdeutige Grammatiken, z.B. verschiedene Ableitungen für<br />

5 − 3 − 2<br />

E ::= n | E − E<br />

mit n ∈ N<br />

Nichtdeterministische Ausgabe (Ergebnisliste)<br />

type Parser = String -> [(Tree, String)]<br />

Ergebnis:<br />

Liste möglicher Syntaxbäume<br />

◮ []: Fehler<br />

◮ [ x ]: eindeutig interpretierbar (Erfolg)<br />

◮ [ x, y, ..<br />

]: mögliche Interpretationen<br />

110


Typabstraktion<br />

Verschiedene Typen von „Eingaben“ c und „Syntaxbäumen“ a<br />

data Parser c a = Parser ( [c] -> [(a, [c])] )<br />

parse :: Parser c a -> [c] -> [(a, [c])]<br />

parse ( Parser f ) s = f s<br />

(oft Char für c)<br />

A Parser for Things<br />

is a functions from Strings<br />

to Lists of Pairs<br />

of Things and Strings!<br />

111


Parser<br />

◮ Elementare Parser<br />

◮ Operationen zur Kombination von Parsern:<br />

◮ sequentielle Kombination<br />

◮ parallele Kombination (Auswahl)<br />

◮ Iteration<br />

112


Elementare Parser<br />

◮ return (immer erfolgreich und eindeutig)<br />

return :: a -> Parser c a<br />

return v = Parser $ \x -> [(v, x)]<br />

◮ reject (nie erfolgreich)<br />

reject :: Parser c a<br />

reject = Parser $ \_ -> []<br />

◮ item (vearbeitet das erste Symbol der Eingabe)<br />

item :: Parser c c<br />

item = Parser $ \x -> case x of<br />

[] -> []<br />

(x : xs) -> [( x, xs )]<br />

113


Anwendung<br />

parse :: Parser String a -> String -> [(a, String )]<br />

parse p ein = p ein<br />

Beispiele:<br />

◮ parse (return 1) "abc"<br />

◮ parse reject "abc"<br />

◮ parse item "abc"<br />

◮ parse item ""<br />

114


Test des ersten Symbols<br />

◮ satisfy (akzeptiert das erste Symbol, falls es die<br />

Bedingung pred erfüllt)<br />

satisfy :: (c -> Bool) -> Parser c c<br />

satisfy pred = do<br />

x c -> Parser c c<br />

expect c = satisfy ( == c )<br />

Beispiele:<br />

◮ parse (expect ’a’) "abc"<br />

◮ parse (expect ’a’) ""<br />

◮ parse (expect ’b’) "abc"<br />

◮ parse (satisfy isDigit) "1a4"<br />

115


Sequentielle Verknüpfung<br />

Verkettung von Sprachen: L ◦ L ′ = {uv | u ∈ L ∧ v ∈ L ′ }<br />

seq :: Parser c a -> ( a -> Parser c b) -> Parser c b<br />

kennen wir schon als bind-Operation für Monaden<br />

>>= :: Parser c a -> ( a -> Parser c b) -> Parser c b<br />

p >>= f = Parser $ \ s -> do<br />

( v, t ) >= ( \v1 -> p2 >>= \v2 -> ...<br />

(\vn -> return (f v1 v2 ... vn))...)<br />

oder in do-Notation:<br />

do v1


parse (parens item) "(r)"<br />

parse (parens p) "(abcd)" 117<br />

Beispiele<br />

p :: Parser Char (Char, Char)<br />

p = do x


Parallele Verknüpfung<br />

Vereinigung von Sprachen: L ∪ L ′<br />

() :: Parser c a -> Parser c a -> Parser c a<br />

p q = Parser $ \ s -><br />

( parse p s ) ++ ( parse q s )<br />

Beispiel:<br />

s :: Parser Char ()<br />

s = do { expect ’a’ ; s ; expect ’b’ ; s }<br />

return ()<br />

parse (do s ; eof) "abab"<br />

118


Iteration<br />

bekannt aus LV Theoretische Informatik:<br />

L ∗ = {ε} ∪ L +<br />

L + = L ◦ L ∗<br />

many :: Parser c a -> Parser c [a]<br />

many p = many1 p return []<br />

many1 :: Parser c a -> Parser c [a]<br />

many1 p = do<br />

x


Akzeptanz formaler Sprachen<br />

s :: Parser Char ()<br />

akzeptiert alle von der Grammatik mit den Regeln<br />

S → aSbS | ε<br />

erzeugten Wörter<br />

s = do { expect ’a’ ; s ; expect ’b’ ; s }<br />

return ()<br />

parse (do s ; eof) "abaabb"<br />

120


Arithmetische Ausdrücke<br />

Grammatik (mit Operator-Präferenzen):<br />

E ::= P(+P) ∗<br />

P ::= F (∗F ) ∗<br />

F ::= (E) | nat<br />

mit Parsec-Bibliothek ( import Text.Parsec)<br />

summe :: Parsec String () Integer<br />

summe = do<br />

xs

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!