Funktionale Programmierung mit Haskell



Ähnliche Dokumente
Programmiersprachen und Übersetzer

Theoretische Grundlagen der Informatik

Funktionale Programmierung mit Haskell

2.11 Kontextfreie Grammatiken und Parsebäume

Grundbegriffe der Informatik

Funktionale Programmierung mit Haskell

Kapitel 2: Formale Sprachen Kontextfreie Sprachen. reguläre Grammatiken/Sprachen. kontextfreie Grammatiken/Sprachen

Theorie der Informatik

Theoretische Informatik I

Theoretische Informatik 2 (WS 2006/07) Automatentheorie und Formale Sprachen 19

Formale Sprachen und Grammatiken

t r Lineare Codierung von Binärbbäumen (Wörter über dem Alphabet {, }) Beispiel code( ) = code(, t l, t r ) = code(t l ) code(t r )

1. Formale Sprachen 1.2 Grammatiken formaler Sprachen

Objektorientierte Programmierung

Motivation. Formale Grundlagen der Informatik 1 Kapitel 5 Kontextfreie Sprachen. Informales Beispiel. Informales Beispiel.

Formale Sprachen. Der Unterschied zwischen Grammatiken und Sprachen. Rudolf Freund, Marian Kogler

Grundbegriffe der Informatik

Kapitel MK:IV. IV. Modellieren mit Constraints

IT-Basics 2. DI Gerhard Fließ

Programmieren in Haskell Einführung

Grundlagen der Programmierung Prof. H. Mössenböck. 14. Schrittweise Verfeinerung

Erwin Grüner

Einführung in die Programmierung

Grundbegriffe der Informatik

Einführung in die Programmierung

Computeranwendung und Programmierung (CuP)

Theoretische Informatik I

Formale Sprachen, reguläre und kontextfreie Grammatiken

Grundlagen der Informatik II. Teil I: Formale Modelle der Informatik

Mathematische Grundlagen der Informatik 2

Algorithmen II Vorlesung am

Algorithmen und Datenstrukturen 2

Grundbegriffe der Informatik

Informatik IV Theoretische Informatik: Formale Sprachen und Automaten, Berechenbarkeit und NP-Vollständigkeit

Zusammenfassung. 1 Wir betrachten die folgende Signatur F = {+,,, 0, 1} sodass. 3 Wir betrachten die Gleichungen E. 4 Dann gilt E 1 + x 1

Was bisher geschah. deklarative Programmierung. funktionale Programmierung (Haskell):

Grundlagen der Programmierung Prof. H. Mössenböck. 3. Verzweigungen

Typdeklarationen. Es gibt in Haskell bereits primitive Typen:

WS 2009/10. Diskrete Strukturen

Einführung in die Programmierung (EPR)

public class SternchenRechteckGefuellt {

ALP I. Funktionale Programmierung

Scala kann auch faul sein

Grundlagen der Programmierung 2. Bäume

Wortproblem für kontextfreie Grammatiken

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Objektorientierte Programmierung. Kapitel 3: Syntaxdiagramme und Grammatikregeln

Funktionale Programmierung

Konzepte der Informatik

Programmieren in C. Macros, Funktionen und modulare Programmstruktur. Prof. Dr. Nikolaus Wulff

Grammatiken. Einführung

Lernziele: Ausgleichstechniken für binäre Bäume verstehen und einsetzen können.

Diana Lange. Generative Gestaltung Operatoren

Grammatiken in Prolog

Grundlagen der Künstlichen Intelligenz

Einfache Ausdrücke Datentypen Rekursive funktionale Sprache Franz Wotawa Institut für Softwaretechnologie

4. Jeder Knoten hat höchstens zwei Kinder, ein linkes und ein rechtes.

7. Formale Sprachen und Grammatiken

Würfelt man dabei je genau 10 - mal eine 1, 2, 3, 4, 5 und 6, so beträgt die Anzahl. der verschiedenen Reihenfolgen, in denen man dies tun kann, 60!.

Beispiele: (Funktionen auf Listen) (3) Bemerkungen: Die Datenstrukturen der Paare (2) Die Datenstrukturen der Paare

7 Rechnen mit Polynomen

VBA-Programmierung: Zusammenfassung

Algorithmische Mathematik

Reihungen. Martin Wirsing. in Zusammenarbeit mit Matthias Hölzl und Nora Koch 11/03

Idee: Wenn wir beim Kopfknoten zwei Referenzen verfolgen können, sind die Teillisten kürzer. kopf Eine Datenstruktur mit Schlüsselwerten 1 bis 10

Suchmaschinen. Universität Augsburg, Institut für Informatik SS 2014 Prof. Dr. W. Kießling 23. Mai 2014 Dr. M. Endres, F. Wenzel Lösungsblatt 6

Programmieren in Haskell

Studentische Lösung zum Übungsblatt Nr. 7

4. 4. Algorithmen und Datenstrukturen in deskriptiven Programmiersprachen

Graphic Coding. Klausur. 9. Februar Kurs A

Matrizennorm. Definition 1. Sei A M r,s (R). Dann heißt A := sup die Matrixnorm. Wir wissen zunächst nicht, ob A eine reelle Zahl ist.

Logische Folgerung. Definition 2.11

Programmierkurs Java

1 Mathematische Grundlagen

Sortieralgorithmen. Inhalt: InsertionSort BubbleSort QuickSort. Marco Block

Compiler, Übersetzer. Allgemeine Erklärung / Definition

Datenbanken Microsoft Access 2010

Vorkurs C++ Programmierung

Datentypen. Agenda für heute, 4. März, Pascal ist eine streng typisierte Programmiersprache

R ist freie Software und kann von der Website.

Einführung in. Logische Schaltungen

Typklassen. Natascha Widder

Informatik 11 Kapitel 2 - Rekursive Datenstrukturen

Objektorientierte Programmierung für Anfänger am Beispiel PHP

CGI Programmierung mit Ha. Markus Schwarz

Das Typsystem von Scala. L. Piepmeyer: Funktionale Programmierung - Das Typsystem von Scala

Wiederholung ADT Menge Ziel: Verwaltung (Finden, Einfügen, Entfernen) einer Menge von Elementen

Einführung in die Algebra

1 topologisches Sortieren

Die Java Stream API. Funktionale Programmierung mit der Stream API des JDK 1.8. Prof. Dr. Nikolaus Wulff

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

1 Syntax von Programmiersprachen

Vorlesung Diskrete Strukturen Graphen: Wieviele Bäume?

Modellierung und Programmierung 1

Folge 19 - Bäume Binärbäume - Allgemeines. Grundlagen: Ulrich Helmich: Informatik 2 mit BlueJ - Ein Kurs für die Stufe 12

Einführung in die Java- Programmierung

368 4 Algorithmen und Datenstrukturen

Künstliche Intelligenz Maschinelles Lernen

Transkript:

Funktionale Programmierung mit Haskell Prof. Dr. Hans J. Schneider Lehrstuhl für Programmiersprachen und Programmiermethodik Friedrich-Alexander-Universität Erlangen-Nürnberg Sommersemester 2011 I. Die Sprache Haskell II. Fallstudien 8. Suchbäume und beliebige Graphen 9. Lambda-Interpretierer 10. Syntaxanalyse 11. Algebraische Spezifikation 12. Semantik operationeller Sprachen 13. Kategorien in Haskell 14. Compilieren funktionaler Programme c Hans J. Schneider 2011

Chomsky-Grammatik Definition: Eine Chomsky-Grammatik ist ein Quadrupel G = (T, N, P, S) mit T, N (endliche, disjunkte) Alphabete terminale und nichtterminale Symbole S N Startsymbol P endliche Teilmenge von V NV V, wobei V = T N ist. Produktionen Definition: Eine kontextfreie Grammatik ist eine Chomsky-Grammatik mit P N V Beispiel (BNF-Schreibweise) E ::= E + T E T T T ::= T F T/F F F ::= v n ( E ) Funktionale Programmierung mit Haskell 10.1

Direkte Ableitbarkeit Sei p = (u, v) P x p y : ( w, z V )(x = wuz y = wvz) Sei G = (T, N, P, S) x y : ( p P )(x G p y) Wenn keine Verwechslung möglich: x y statt x G y Beispiel: E E + T T + T T + T F v + T F... E E + T E + T F T + T F v + T F... Funktionale Programmierung mit Haskell 10.2

Ableitbarkeit Definition der Ableitbarkeit: x y : ( n 0)( w 0, w 1,..., w n V ) (w 0 = x ( 1 i n)(w i 1 w i ) w n = y) Andere Schreibweisen: Feste Anzahl von Schritten: In der Literatur auch: = n Menge der erzeugten Zeichenreihen: L(G) := {w S G w w T } Funktionale Programmierung mit Haskell 10.3

Ableitungsbaum Ableitungsbaum = Graphische Darstellung einer Ableitung bei kontextfreien Grammatiken E E + T T T F p 1 p 3 p 4 p 6 p 6 p 7 F F v p 7 p 8 v n Zusammenhang: Wurzel = Startsymbol Innere Knoten = Nichtterminale Symbole Blätter = Terminale Symbole Verkettung der Blätter = abgeleitete Zeichenreihe Funktionale Programmierung mit Haskell 10.4

Kontextfreie Grammatik in Haskell: Symbole Wir unterscheiden die terminalen und die nichtterminalen Symbole: data Symbol a b = T a N b deriving (Eq,Ord,Read) Wir können unterschiedliche Symbolvorräte wählen: Symbol Char Char verwendet sowohl für terminale als auch für nichtterminale Symbole Einzelzeichen. Symbol Char String verwendet für nichtterminale Symbole Zeichenketten. Bei der Ausgabe sollen die Konstruktoren entfallen: instance (Show a, Show b) => Show (Symbol a b) where show (T x) = show x show (N x) = show x Abfrage: nonterm :: Symbol a b -> Bool nonterm (T _) = False nonterm _ = True Funktionale Programmierung mit Haskell 10.5

Kontextfreie Produktionen in Haskell Produktionen: data Prod a b = Prod (Symbol a b) [Symbol a b] deriving Eq Aufteilung in linke und rechte Seite: lhs :: Prod a b -> (Symbol a b) lhs (Prod x ys) = x rhs :: Prod a b -> [Symbol a b] rhs (Prod x ys) = ys Drucken von Produktionen: instance (Show a, Show b) => Show (Prod a b) where show (Prod y zs) = show y ++ " ==> " ++ show zs Beispiel: Grammar> rhs prod1 ["expr", +,"expr"] Grammar> prod1 "expr" ==> "expr" + "expr" Funktionale Programmierung mit Haskell 10.6

Kontextfreie Grammatik in Haskell Man kann Grammatiken auf unterschiedliche Weise implementieren. Also ist es sinnvoll, eine Typklasse zu definieren: class Grammar grammar where startsymbol :: grammar a b -> Symbol a b prettyprintgrammar :: (Show a, Show b) => grammar a b -> IO () Einfache Implementierung: Grammatik als Liste von Produktionen: data ProdList a b = ProdList [Prod a b] Vereinfachung: Startsymbol = linke Seite der ersten Produktion instance Grammar ProdList where startsymbol (ProdList[]) = error "empty grammar" startsymbol (ProdList (r:rs)) = lhs r prettyprintgrammar g = putstr (prtgram g) where prtgram (ProdList []) = "" prtgram (ProdList (r:rs)) = (show r) ++ "\n" ++ (prtgram (ProdList rs)) Funktionale Programmierung mit Haskell 10.7

Kontextfreie Grammatik: Beispiel Einfaches Beispiel: grammar2 :: ProdList Char String grammar2 = ProdList [ Prod (N "expr") [N "expr", T +, N "term"], Prod (N "expr") [N "term"], Prod (N "term") [N "term", T *, N "fact"], Prod (N "term") [N "fact"], Prod (N "fact") [T n ], Prod (N "fact") [T v ], Prod (N "fact") [T (, N "expr", T ) ] ] Funktionale Programmierung mit Haskell 10.8

Bottom-Up-Aufbau von Bäumen Beispiel: T F = T T F F v F v n n Zusammenfassen von Bäumen mittels einer Produktion: reduce :: (Eq a, Eq b) => (Prod a b, [h (Symbol a b)]) -> h (Symbol a b) reduce((prod lhs rhs), subtrees) = if map root subtrees == rhs then ArbNode(lhs, subtrees) else error "production not applicable" StandArbTree wird Instanz von DerivTree. Funktionale Programmierung mit Haskell 10.9

Top-Down-Entwicklung von Bäumen Beispiel: E T E + T E T E + T T F Welches T ist gemäß der Produktion T T F zu ersetzen? Dewey-Indizierung: [] [1] [2] [1, 1] [3] [3, 1] [3, 2] [3, 3] Funktionale Programmierung mit Haskell 10.10

Expandieren an einer bestimmten Stelle Typdefinition: type DeweyIndex = [Int] expand :: (Eq a, Eq b) => (h (Symbol a b), DeweyIndex, Prod a b) -> h (Symbol a b) Implementieren der Expandierung: expand(t, [], (Prod lhs rhs)) = if (root t) == lhs then ArbNode(lhs, map newleaf rhs) else error "Production not applicable" expand(t, i:d, p) = if i > length (successors t) i < 1 then error "Wrong Dewey index" else ArbNode(root t, replace (successors t, i, p)) where replace(ti:r, 1, p) = expand(ti, d, p) : r replace(f:r, i, p) = f: replace(r, i-1, p) Funktionale Programmierung mit Haskell 10.11

Finden eines bestimmten Blattes findleftmost :: (Eq a, Eq b) => Symbol a b -> h (Symbol a b) -> DeweyIndex findleftmost x t = if found then d else error "Element not found" where (found, d) = find(x, t) find(x, t) = if (height t ) == 0 then (False, []) {- 2. Komponente ohne Bedeutung -} else if (height t ) == 1 then if (root t) == x then (True, []) else (False, []) else helper(x, successors t, 1) helper(x, [], i) = (False, []) helper(x, f:st, i) = if foundinthis then (True, i:d ) else helper(x, st, i+1) where (foundinthis, d ) = find(x, f) Funktionale Programmierung mit Haskell 10.12

Erzeugen einer Linksableitung Setze die Produktion soweit links wie möglich ein: expandleftmost(t, p) = expand(t, findleftmost x t, p) where x = lhs p Beispiele: t0 = starttree grammar2 t1 = expandleftmost(t0, Prod (N "expr") [N "expr", T +, N "term"]) Grammar> t0 ("expr") Grammar> t1 ("expr" ("expr") ( + ) ("term")) Grammar> expandleftmost(t1, Prod (N "expr") [N "expr", T +, N "term"]) ("expr" ("expr" ("expr") ( + ) ("term")) ( + ) ("term")) Funktionale Programmierung mit Haskell 10.13

Klasse der Ableitungsbäume class (Tree h) => DerivTree h where starttree :: Grammar a b -> h (Symbol a b) termnode :: Symbol a b -> h (Symbol a b) reduce :: (Eq a, Eq b) => (Prod a b, [h (Symbol a b)]) -> h (Symbol a b) expand :: (Eq a, Eq b) => (h (Symbol a b), DeweyIndex, Prod a b) -> h (Symbol a b) findleftmost :: (Eq a, Eq b) => Symbol a b -> h (Symbol a b) -> DeweyIndex expandleftmost :: (Eq a, Eq b) => (h (Symbol a b), Prod a b) -> h (Symbol a b) instance DerivTree StandArbTree where starttree g = ArbNode(startSymbol g, []) termnode (T c) = ArbNode(T c, []) termnode (N _) = error "termnode needs terminal symbol"... Funktionale Programmierung mit Haskell 10.14

Cocke-Kasami-Younger: Definitionen Chomsky-Normalform: Alle Produktionen sind von der Form: A ::= B C a Syntaxanalyse nach Cocke, Kasami und Younger: Gegeben: w = t 1 t 2... t n Zentrale Datenstruktur: Matrix m ij ( 0 i < j n)(m ij = {A A N A t i+1... t j }) w L(G) S m 0n Effektive Konstruktion der m ij : m i,i+1 := {A A ::= t i+1 } m ij := {A ( i < k < j)( B m ik )( C m kj )(A ::= BC)} Funktionale Programmierung mit Haskell 10.15

Cocke-Kasami-Younger: Rechenschema t 1 t 2 t n 0 1 m 0n n Funktionale Programmierung mit Haskell 10.16

Beispielgrammatik Übliche Formulierung (BNF): S ::= AB BB A ::= CC AB a B ::= BB CA b C ::= BA AA b Beispiel eines Wortes mit mehreren Ableitungen: A a S B B B A A S B B b b b a b Funktionale Programmierung mit Haskell 10.17

Beispielgrammatik in Haskell Wir speichern zur Vereinfachung die Grammatik als Liste der Produktionen: data Prod a b = Prod (Symbol a b) [Symbol a b] deriving Eq Haskell-Formulierung des Beispiels: g2 = ProdList [ Prod (N S ) [N A, N B ], Prod (N S ) [N B, N B ], Prod (N A ) [N C, N C ], Prod (N A ) [N A, N B ], Prod (N A ) [T a ], Prod (N B ) [N B, N B ], Prod (N B ) [N C, N A ], Prod (N B ) [T b ], Prod (N C ) [N B, N A ], Prod (N C ) [N A, N A ], Prod (N C ) [T b ] ] Funktionale Programmierung mit Haskell 10.18

Kern des CKY-Algorithmus Effektive Konstruktion der m ij : m i,i+1 := {A A ::= t i+1 } m ij := {A ( i < k < j)( B m ik )( C m kj )(A ::= BC)} Implementierung der effektiven Konstruktion: cky(i,j) = if j == i+1 then [a (Prod a [T b]) <- listofprods, b == word!! i ] else concat [ [a (Prod a [b,c]) <- listofprods, elem b (cky(i,k)) && elem c (cky(k,j)) ] k <- [i+1.. j-1] ] where (ProdList listofprods) = grammar Ein Feld kann ein Element mehrfach enthalten. Funktionale Programmierung mit Haskell 10.19

CKY-Algorithmus in Haskell Top-Level-Funktion im Modul CKYParsing: ckyisword grammar word = elem (startsymbol grammar) (cky(0, length word)) where cky(i,j) =... Beispiel: CKYParsing> ckyisword g2 "abb" True Kann man den CKY-Kern so ändern, dass alle Bäume ausgegeben werden? Funktionale Programmierung mit Haskell 10.20

CKY mit Bäumen Wir speichern in jedem Feld der Matrix alle Teilbäume mit der Eigenschaft ( 0 i < j n)(m ij = {A A N A t i+1... t j }) cky(i,j) = if j == i+1 then [ArbNode(a, [termnode (T b)]) (Prod a [T b]) <- listofprods, b == word!! i ] else concat [ [reduce (Prod a [b,c], [t1, t2]) t1 <- cky(i,k), t2 <- cky(k,j), (Prod a [b,c]) <- listofprods, b == root t1 && c == root t2 ] k <- [i+1.. j-1] ] where (ProdList listofprods) = grammar Funktionale Programmierung mit Haskell 10.21

CKY mit Bäumen (II) Die Analysefunktion muss die Bäume aus m 0n heraussuchen, die mit dem Startsymbol beginnen. ckytrees grammar word = if length(result) == 0 then error "Word not derivable" else result where result = validtrees (cky(0, length(word))) Bemerkungen: validtrees [] = [] validtrees (h:t) = if (root h) == (startsymbol grammar) then h : (validtrees t) else validtrees t cky(i,j) =... cky ist lokal definiert und kann daher in beiden Algorithmen verwandt werden. Benutze bei validtrees die filter-funktion! Die Lösung ist sehr ineffizient. Funktionale Programmierung mit Haskell 10.22

Ausdrucken aller Ableitungsbäume Erzeugung von Leerzeilen zwischen den Bäumen: printckytrees grammar word = putstr(printdertrees (ckytrees grammar word)) where -- printdertrees :: [StandArbTree Char] -> String printdertrees [] = "\n" printdertrees [t] = show t ++ "\n" printdertrees (t1:rest) = (show t1) ++ "\n\n" ++ (printdertrees rest) Beispiel einer (mehrdeutigen) Analyse: CKYParsing> printckytrees g2 "abb" ( S ( A ( a )) ( B ( B ( b )) ( B ( b )))) ( S ( A ( A ( a )) ( B ( b ))) ( B ( b ))) Funktionale Programmierung mit Haskell 10.23