Lazy Pattern Matching. 10. Dezember 2014

Ähnliche Dokumente
Funktionale Programmierung

Programmieren in Haskell. Stefan Janssen. Strukturelle Rekursion. Universität Bielefeld AG Praktische Informatik. 10.

Programmieren in Haskell Einstieg in Haskell

Programmieren in Haskell

Funktionale Programmierung mit Haskell

Programmieren in Haskell

Programmieren in Haskell Programmiermethodik

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

Funktionale Programmierung ALP I. Funktionen höherer Ordnung. Teil 2 SS Prof. Dr. Margarita Esponda. Prof. Dr.

Tag 7. Pattern Matching und eigene Datentypen

Einführung in die Funktionale Programmierung mit Haskell

Felder. November 5, 2014

Allgemeine Hinweise: TECHNISCHE UNIVERSITÄT MÜNCHEN. Name Vorname Studiengang Matrikelnummer. Hörsaal Reihe Sitzplatz Unterschrift

Crashkurs Haskell Mentoring WiSe 2016/17. Anja Wolffgramm Freie Universität Berlin

Funktionale Programmiersprachen

2.5 Listen. Kurzschreibweise: [42; 0; 16] Listen werden mithilfe von [] und :: konstruiert.

Programmieren in Haskell

Funktionale Programmierung

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

Was bisher geschah Funktionale Programmierung in Haskell: Algebraische Datentypen Pattern Matching Polymorphie Typklassen Rekursive Datentypen:

Vorsicht bei redundanten und unvollständigen Matches!

Das Damenproblem - funktional und logisch

Funktionen höherer Ordnung

Welche Informatik-Kenntnisse bringen Sie mit?

Lösung Probeklausur Informatik I

ALP I. Funktionale Programmierung

Agenda. 1 Einleitung. 2 Binäre Bäume. 3 Binäre Suchbäume. 4 Rose Trees. 5 Zusammenfassung & Ausblick. Haskell Bäume. Einleitung.

11 Fallstudie: Reguläre Ausdrücke

Induktion und Rekursion

Grundprinzipien der funktionalen Programmierung

WS 2011/2012. Georg Sauthoff 1. October 18, 2011

Berechnungsschemata: Funktion als Parameter abstrahiert Operation im Schema, wird bei Aufruf des Schemas konkretisiert

Programmieren I. Kapitel 5. Kontrollfluss

Grundlagen der Programmierung 2 (1.C)

Funktionale Programmierung mit Haskell. Jan Hermanns

Programmieren in Haskell Einführung

Programmtransformationen und Induktion in funktionalen Programmen

ALP I Einführung in Haskell

Hilfsblatt für C++ Prüfungen im 5. Semester

Informatik I: Einführung in die Programmierung

C++ Teil 2. Sven Groß. 16. Apr IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil Apr / 22

Algorithmen & Programmierung. Rekursive Funktionen (1)

Zahlen in Haskell Kapitel 3

Verschlüsseln eines Bildes. Visuelle Kryptographie. Verschlüsseln eines Bildes. Verschlüsseln eines Bildes

Datenstrukturen & Algorithmen

Haskell Seminar Abstrakte Datentypen. Nils Bardenhagen ms2725

Haskell, Typen, und Typberechnung. Grundlagen der Programmierung 3 A. Einige andere Programmiersprachen. Typisierung in Haskell

Typdeklarationen. Es gibt in Haskell bereits primitive Typen:

Visual Basic Basisbefehle Hinweis: Der Text in eckigen Klammern [ ] ist variabel, z.b. [var] => 5.3. Eckige Klammern sind stets wegzulassen!

ROGER GILLIAR / MCS GMBH HASKELL FÜR JAVA PROGRAMMIERER

zu große Programme (Bildschirmseite!) zerlegen in (weitgehend) unabhängige Einheiten: Unterprogramme

Escher funktionale und logische Programmierung

DataTables LDAP Service usage Guide

Einstieg in die Programmierung mit Visual Basic.NET

1 - FortProg ist: [ ] objekt-orientiert; [ ] funktional; [ ] logisch; [ ] manchmal nicht auszuhalten

zu große Programme (Bildschirmseite!) zerlegen in (weitgehend) unabhängige Einheiten: Unterprogramme

Scala kann auch faul sein

Lösungsvorschlag Serie 2 Rekursion

Organisatorisches. drei Gruppen Gruppe 1: 10:10-11:40, Gruppe 2: 11:45-13:15 Gruppe 3: 13:20-14:50

Funktionale Programmierung mit Haskell

Wie funktioniert das Sortieren einer Reihe von Zufallszahlen mit Quicksort?

Institut für Programmierung und Reaktive Systeme 19. August Programmier-Labor. 1. Übungsblatt

Tutorium - Haskell in der Schule. Ralf Dorn - Dennis Buchmann - Felix Last - Carl Ambroselli

Entwurfsmuster und Frameworks Singleton

Vorlesung Unix-Praktikum

Programmierung 1 (Wintersemester 2015/16) Wiederholungstutorium Lösungsblatt 13 (Queues, Binary Search)

Präsentation Interfaces

Programmieren in C++ Überladen von Methoden und Operatoren

Installation und Benutzung AD.NAV.ZipTools

Überblick. 5. Objekt und Klasse, Elementfunktionen

Einführung in die Programmierung Wintersemester 2011/12

Algorithmen und Datenstrukturen 1. EINLEITUNG. Algorithmen und Datenstrukturen - Ma5hias Thimm 1

Einstieg in die Informatik mit Java

Tutoraufgabe 1 (Datenstrukturen in Haskell):

Grundlagen der Informatik

Einstieg in die Informatik mit Java

Kontextfreie Grammatiken

Algorithmen und ihre Programmierung

Tag 8. Beispiel: Tabellen formatieren

Einführung Servlets. JEE Vorlesung Teil 2. Ralf Gitzel

13. Funktionale Konzepte in Java

Zeichendarstellung. Zeichen sind Zahlen (in C) Zeichen und switch

Informatik I. Informatik I Iteration vs. Rekursion. Iteration vs. Rekursion Iteration vs. Rekursion. 20. Iteration vs.

Grundlagen der Programmierung in C Funktionen

Praktikum Funktionale Programmierung Teil 1: Lexen und Parsen

Grundlagen der Informatik Vorlesungsskript

Speicherklassen (1) Lokale Variablen

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = Euro ergeben.

Lösungsvorschläge Blatt 4

Großübung zu Einführung in die Programmierung

Java: Eine kurze Einführung an Beispielen

C.3 Funktionen und Prozeduren

Algorithmen und Datenstrukturen 1 Kapitel 3

Interpreter - Gliederung

Einführung in die Programmierung mit Java

1 RPC-Protokoll-Definitionssprache (Protocol Definition Language )

Datenstrukturen & Algorithmen Lösungen zu Blatt 5 FS 14

Objektorientierte Programmierung

Praktische Informatik 3: Einführung in die Funktionale Programmierung Vorlesung vom : Rekursive Datentypen

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 11/12 1. Kapitel 11. Listen. Listen

Transkript:

Lazy Lazy s Universität Bielefeld AG Praktische Informatik 10. Dezember 2014

Themen-Vorschau : as-s und lazy s Client-Server-Programmierung Lazy s

matching (alias Mustervergleich) kennen wir bereits aus Funktionsgleichungen aus case-ausdrücken Ein (Muster) ist ein Ausdruck bestehend aus Variablen, der anonymen Variablen _ ( Joker ) Konstruktoren aller Datentypen Zahlen, Characters... also keine Funktionen, die nicht Konstruktoren sind... und keine Variable mehrfach, ausgenommen _ Lazy s

Ergonomie des matching leistet zweierlei Fallunterscheidung in übersichtlicher Form Nutzung der Reihenfolge bei überlappenden Mustern Bindung von Muster-Variablen an Substrukturen des geprüften Werts 1 leaves ( Leaf a) = [a] 2 leaves ( Br ( Leaf a) y) = a : leaves y 3 leaves (Br (Br x y) z) = leaves (Br x (Br y z)) Lazy s

As-s 1 Manchmal will man Muster verwenden und einen Namen für den (unzerlegten) Argumentwert haben 2 suffixes (x:xs) = (x:xs ): suffixes xs erzeugt eine überflüssige (:) Operation, vergeudet Zeit und verschwendet Platz. Besser mit as-pattern Lazy s suffixes z@(x:xs) = z: suffixes xs Nun ist das schon vorhandene x:xs unter dem Namen z zu haben.

As-s 1 Manchmal will man Muster verwenden und einen Namen für den (unzerlegten) Argumentwert haben 2 suffixes (x:xs) = (x:xs ): suffixes xs erzeugt eine überflüssige (:) Operation, vergeudet Zeit und verschwendet Platz. Besser mit as-pattern Lazy s suffixes z@(x:xs) = z: suffixes xs Nun ist das schon vorhandene x:xs unter dem Namen z zu haben. Nebenbei: Welche Komplexität hat die Berechnung von suffixes x? Und welche die Ausgabe des Ergebnisses?

und Auswertungreihenfolge Vergleich eines Musters mit einem Wert erfordert, dass der Wert ausgerechnet wird, aber nur soweit es für den Vergleich nötig ist (Laziness) Verwendung von Mustern hat also Auswirkung auf die Berechenungsreihenfolge Lazy s

Abweisbare und nicht abweisbare Muster a.k.a. refutable versus irrefutable patterns Ein Muster ohne Konstruktoren (also x, _ ) passt auf jedem Wert und heißt unabweisbar Ein Muster mit Konstruktoren heißt abweisbar Ist eine Funktion mit unabweisbaren Mustern definiert, ist sie immer ein Redex. Beispiele: 1 square x = x * x 2 double f = f. f 3 five _ = 5 NB: Man kann alle Funktionen auf der linken Seite mit unabweisbaren Mustern schreiben, wenn man stattdessen case-ausdrücke auf der rechten Seite verwendet. Lazy s

und Terminierung (1) Erinnerung: Die Auswertungsstrategie in einer funktionalen Sprache hat keinen Einfluss auf den ggf. berechneten Wert, wohl aber auf die Terminierung der Berechnung. Ein Mustervergleich kann positive oder negativ ausgehen, oder divergieren Alle Muster in einer Gleichung werden top-down, links-rechts verglichen Geht ein Vergleich negativ aus, ist die aktuelle Gleichung nicht anwendbar, und es wird die nachfolgende Gleichung versucht Ruft der Vergleich eine nicht-endende Berechnung hervor, divergiert er und das Ergebnis der Gesamtrechnung ist undefiniert. Passen alle Muster einer Gleichung, wird sie angewendet Lazy s

Bottom Hier eine Definition des undefinierten Werts 1 > bot = bot bot, ausgesprochen bottom ist der gänzlich undefinierte Wert. Seine Berechnung terminiert nicht, und produziert auch keinen Konstruktor. Lazy s

Bottom Hier eine Definition des undefinierten Werts 1 > bot = bot bot, ausgesprochen bottom ist der gänzlich undefinierte Wert. Seine Berechnung terminiert nicht, und produziert auch keinen Konstruktor. Lazy s Was wäre ein teilweise undefinierter Wert?

Bottom Hier eine Definition des undefinierten Werts 1 > bot = bot bot, ausgesprochen bottom ist der gänzlich undefinierte Wert. Seine Berechnung terminiert nicht, und produziert auch keinen Konstruktor. Lazy s Was wäre ein teilweise undefinierter Wert? Nebenbei: Welchen Typ hat bot?

und Terminierung (2) Vergleiche 1 take 0 _ = [] 2 take _ [] = [] 3 take n (x:xs) = x : take (n -1) xs und mit vertauschten Zeilen 1 take _ [] = [] 2 take 0 _ = [] 3 take n (x:xs) = x : take (n -1) xs Einen Unterschied gibt es nur, wenn eines der Argumente undefiniert ist... Lazy s

Unterschiedliches Terminierungsverhalten 1 take 0 bot ==> [] 2 take 0 bot = = > undefiniert 3 4 take bot [] = = > undefiniert 5 take bot [] ==> [] Lazy s Der Haskell Prelude implementiert die Version take.

Lazy s a.k.a. Muster mit verzögertem Vergleich Problem: Man möchte eine Funktion mit einem Muster definieren und zwar für ein Argument, das durch die Anwendung der Funktion erst berechnet wird Zwar steht fest, dass das Muster erfüllt sein wird, jedoch zum Zeitpunkt der Funktionsaufrufs muss für den Mustervergleich die gleiche Funktion wieder aufgerufen werden... Lazy s Wo kommt so etwas überhaupt vor?

Client-Server-Anwendungen Client-Server-Anwendungen sind parallel laufende Programme, die über Ströme kommunizieren Nachrichten an einander Requests und Responses werden wechselseitig erzeugt und gelesen Sie werden in Strömen (streams) verwaltet. Ströme sind einfach lazy Listen, in andern Sprachen weden sie als spezieller Datentyp zur Verfügung gestellt. Lazy s

Zahlen raten als client- Programm (1) Ratespiel: Finde eine Zahl n aus dem Intervall [0..N] durch Fragen der Art Ist n z? mit geschickt gewählten Vergleichszahlen z. Lazy s

Zahlen raten als client- Programm (1) Ratespiel: Finde eine Zahl n aus dem Intervall [0..N] durch Fragen der Art Ist n z? mit geschickt gewählten Vergleichszahlen z. 63 Lazy s

Zahlen raten als client- Programm (1) Ratespiel: Finde eine Zahl n aus dem Intervall [0..N] durch Fragen der Art Ist n z? mit geschickt gewählten Vergleichszahlen z. Rollenverteilung: Client: Erzeugt Fragen und merkt sich das Ergebnis. Seine Strategie: Intervall-Halbierung; sie führt garantiert in O(log(N)) Schritten zum Ziel. Server: Kennt n und beantwortet Fragen Ist n z? mit True oder False. Der Server antwortet wahrheitsgemäß. Kommunikation zwischen Client und Server über zwei Ströme: questions und answers. Lazy s

Zahlen raten als client- Programm (2) Eine Frage hat die Form (l,g,u) und bedeutet ausführlich: Ich weiß dass n [l..u] und frage ob n g. g ist dabei die Intervallmitte, und wird, je nach Antwort, für die nächste Frage ins linke oder rechte Halbintervall verlegt. Das Ende erkennt der Client daran, dass das Intervall sich nicht mehr ändert. 1 > minn = 0 2 > maxn = 1024 3 > t a k e d i f f [ ] = [ ] 4 > t a k e d i f f [ x ] = [ x ] 5 > t a k e d i f f ( x : y : x s ) = x : i f y == x then [ ] e l s e t a k e d i f f ( y : x s ) takediff nimmt den Präfix einer Liste bis zur ersten Wiederholung Lazy s

Zahlen raten als client- Programm (2) Wir definieren die Prozesse ask und reply, die über die Listen questions und answers kommunizieren. 1 > g u e s s n = t a k e d i f f (map ( \ (_, g, _) > g ) q u e s t i o n s ) where 2 > a n s w e r s = r e p l y q u e s t i o n s 3 > r e p l y ( ( _, g, _ ) : qs ) = ( n <= g ) : r e p l y qs 4 5 > q u e s t i o n s = ask i n i t i a l a n s w e r s where 6 > i n i t i a l = ( minn, (maxn + minn ) div 2, maxn) 7 > ask ( l, g, u ) ( a : as ) = ( l, g, u ) : ask newguess as where 8 > newguess = i f a then ( l, ( l + g ) div 2, g ) 9 > e l s e ( g+1, ( g+1 + u ) div 2, u ) Lazy s

Zahlen raten als client- Programm (2) Wir definieren die Prozesse ask und reply, die über die Listen questions und answers kommunizieren. 1 > g u e s s n = t a k e d i f f (map ( \ (_, g, _) > g ) q u e s t i o n s ) where 2 > a n s w e r s = r e p l y q u e s t i o n s 3 > r e p l y ( ( _, g, _ ) : qs ) = ( n <= g ) : r e p l y qs 4 5 > q u e s t i o n s = ask i n i t i a l a n s w e r s where 6 > i n i t i a l = ( minn, (maxn + minn ) div 2, maxn) 7 > ask ( l, g, u ) ( a : as ) = ( l, g, u ) : ask newguess as where 8 > newguess = i f a then ( l, ( l + g ) div 2, g ) 9 > e l s e ( g+1, ( g+1 + u ) div 2, u ) Diese Version funktioniert nicht warum? Lazy s

Verklemmung! Der Aufruf von ask (l,g,u) (a:as) stellt eine Frage ((l,g,u)), die von reply beantwortet wird (a) fragt jedoch in seinem rechten Muster bereits nach dieser Antwort ((a:as)), um aus ihr die nächste Frage (newguess) zu generieren Das pattern matching beim Aufruf von ask kommt zu frueh: es verlangt ein Ergbnis von reply, bevor der gegebene Aufruf von ask das erste Element von questions generiert hat. reply seinerseits verlangt ein Ergebnis von ask... Lazy s

Zahlen raten als client- Programm (3) Vermeidung des übereifrigen Musters: 1 > guess n = t a k e d i f f (map ( \ (_, g, _) > g ) q u e s t i o n s ) where 2 > a n s w e r s = r e p l y q u e s t i o n s 3 > 4 r e p l y ( ( _, g, _ ) : qs ) = ( n <= g ) : r e p l y qs 5 > q u e s t i o n s = ask i n i t i a l a n s w e r s where 6 > i n i t i a l = ( minn, (maxn + minn ) div 2, maxn) 7 > ask ( l, g, u ) as = ( l, g, u ) : ask newguess ( t a i l as ) where Lazy s 8 > a = head as 9 > newguess = i f a then ( l, ( l + g ) div 2, g ) 10 > e l s e ( g+1, ( g+1 + u ) div 2, u ) ask kann nun starten, ohne zuerst nach der Zerlegung der answers-liste as zu fragen. Also kann die Frage ausgegeben und daraus die erste Antwort erzeugt werden, bevor mit head as nach ihr gefragt wird

Lazy s Durch (...) Lazy s wird ein als lazy markiert. Das löst unser Verklemmungsproblem.

Zahlen raten als client- Programm (4) Der gleiche Effekt mit lazy pattern ~(a:as) 1 > guess n = t a k e d i f f (map ( \ (_, g, _) > g ) q u e s t i o n s ) where 2 > a n s w e r s = r e p l y q u e s t i o n s 3 > r e p l y ( ( _, g, _ ) : qs ) = ( n <= g ) : r e p l y qs 4 5 > q u e s t i o n s = ask i n i t i a l a n s w e r s where 6 > i n i t i a l = ( minn, (maxn + minn ) div 2, maxn) 7 > ask ( l, g, u ) ~( a : as ) = ( l, g, u ) : ask newguess as where Lazy s 8 > newguess = i f a then ( l, ( l + g ) div 2, g ) 9 > e l s e ( g+1, ( g+1 + u ) div 2, u ) der lazy pattern ~(a:as) wird beim Aufruf als erfüllt angenommen erst wenn a oder as gebraucht wird, findet der Abgleich statt.

Lazy s Lazy patterns, ~(...) sind unabweisbar. Ihre Überprüfung findet nur statt, wenn eine Komponente daraus gebraucht wird Scheitert sie, bricht die Rechnung ab. Eine weitere Mustergleichung nach einer Gleichung mit einem lazy macht also keinen Sinn. Lazy s

Top level pattern binding: immer lazy Werden Muster nicht auf Argumentposition, sondern in der Definition von Konstanten benutzt, sind sie automatisch lazy: fibp@(1:tfibp) = 1:1:[a+b (a,b) <- zip fibp tfibp ] Lazy s

Top level pattern binding: immer lazy Werden Muster nicht auf Argumentposition, sondern in der Definition von Konstanten benutzt, sind sie automatisch lazy: fibp@(1:tfibp) = 1:1:[a+b (a,b) <- zip fibp tfibp ] Hier haben wir einen as-, der eine konstante, unendliche Liste definiert,...... die Liste der Fibonacci-Zahlen. Das Muster bindet die Gesamtliste an den Namen fibp, zugleich ihren tail an den Namen tfibp die linke Seite fragt, ob die Liste nicht leer ist, aber dank der laziness des Musters wird dies erst geprüft, wenn tfibp rechts benutzt wird Lazy s

Top level pattern binding: immer lazy Werden Muster nicht auf Argumentposition, sondern in der Definition von Konstanten benutzt, sind sie automatisch lazy: fibp@(1:tfibp) = 1:1:[a+b (a,b) <- zip fibp tfibp ] Hier haben wir einen as-, der eine konstante, unendliche Liste definiert,...... die Liste der Fibonacci-Zahlen. Das Muster bindet die Gesamtliste an den Namen fibp, zugleich ihren tail an den Namen tfibp die linke Seite fragt, ob die Liste nicht leer ist, aber dank der laziness des Musters wird dies erst geprüft, wenn tfibp rechts benutzt wird Vergleiche: let a@(1:as) = 1:[] in 2:a let a@(0:as) = 1:[] in 2:a Lazy s