Untitled - Tires65.com

Werbung
eXamen.press
eXamen.press ist eine Reihe, die Theorie und
Praxis aus allen Bereichen der Informatik für
die Hochschulausbildung vermittelt.
Peter Pepper
Petra Hofstedt
Funktionale
Programmierung
Sprachdesign und Programmiertechnik
Mit 57 Abbildungen und 18 Tabellen
123
Peter Pepper
Petra Hofstedt
Technische Universität Berlin
Fakultät IV – Elektrotechnik und Informatik
Institut für Softwaretechnik und Theoretische Informatik
Franklinstraße 28/29
10587 Berlin
[email protected]
[email protected]
Bibliografische Information der Deutschen Bibliothek
Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen
Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über
http://dnb.ddb.de abrufbar.
ISSN 1614-5216
ISBN-10 3-540-20959-X Springer Berlin Heidelberg New York
ISBN-13 978-3-540-20959-1 Springer Berlin Heidelberg New York
Dieses Werk ist urheberrechtlich geschützt. Die dadurch begründeten Rechte, insbesondere
die der Übersetzung, des Nachdrucks, des Vortrags, der Entnahme von Abbildungen und
Tabellen, der Funksendung, der Mikroverfilmung oder der Vervielfältigung auf anderen Wegen und der Speicherung in Datenverarbeitungsanlagen, bleiben, auch bei nur auszugsweiser
Verwertung, vorbehalten. Eine Vervielfältigung dieses Werkes oder von Teilen dieses Werkes
ist auch im Einzelfall nur in den Grenzen der gesetzlichen Bestimmungen des Urheberrechtsgesetzes der Bundesrepublik Deutschland vom 9. September 1965 in der jeweils geltenden
Fassung zulässig. Sie ist grundsätzlich vergütungspflichtig. Zuwiderhandlungen unterliegen
den Strafbestimmungen des Urheberrechtsgesetzes.
Springer ist ein Unternehmen von Springer Science+Business Media
springer.de
© Springer-Verlag Berlin Heidelberg 2006
Printed in Germany
Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesem
Werk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche
Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachten
wären und daher von jedermann benutzt werden dürften. Text und Abbildungen wurden
mit größter Sorgfalt erarbeitet. Verlag und Autor können jedoch für eventuell verbliebene
fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine
Haftung übernehmen.
Satz: Druckfertige Daten der Autoren
Herstellung: LE-TEX, Jelonek, Schmidt & Vöckler GbR, Leipzig
Umschlaggestaltung: KünkelLopka Werbeagentur, Heidelberg
Gedruckt auf säurefreiem Papier 33/3142 YL – 5 4 3 2 1 0
Für Claudia
Meinen Eltern
Christel und Klaus Hofstedt
Vorwort
Lernen ist wie Rudern gegen den Strom; sobald
man damit aufhört, treibt man zurück.
Chinesische Weisheit
Auch wenn es sich bei diesem Text in gewissem Sinn um die Fortführung des
einführenden Lehrbuchs [111], so ist sein Ziel doch ein ganz anderes. In dem
Vorgängerbuch [111] geht es vor allem darum, dem Anfänger einen Einstieg
in das konkrete Programmieren mit existierenden Funktionalen Sprachen zu
geben. Dafür werden drei Sprachen benutzt: opal, ml und haskell.
Das vorliegende Buch wendet sich an fortgeschrittene Leser, die mehr über
Funktionale Sprachen – und nicht nur diese – lernen wollen. Und das betrifft
nicht nur real existierende Sprachen, sondern – was noch wichtiger ist – Konzepte, die heute untersucht, diskutiert und ausgearbeitet und in der einen oder
anderen Weise ihren Weg in künftige Sprachen finden werden.
Der Weg, den wir dazu wählen, ist, eine fiktive Sprache zu behandeln,
die sich zwar sehr stark an bekannten Sprachen – vor allem wieder an opal,
ml und haskell – orientiert, aber in entscheidenden Punkten über sie hinaus geht und neue Ideen realisiert. Der Nachteil ist, dass es keinen Compiler
gibt, den man aus dem Internet herunterladen könnte, um alles, was hier beschrieben ist, auszuprobieren. Dafür kann man aber verschiedene Konzepte
nebeneinander sehen, die sich sonst nur in getrennten Sprachen jeweils für
sich alleine studieren lassen. Darüber hinaus sieht man Konzepte im Kontext
einer Gesamtsprache, die sonst nur in losgelösten wissenschaftlichen Papieren
zu betrachten sind.
Aber natürlich wäre es sehr unbefriedigend, wenn es sich bei den von uns
diskutierten Themen nur um akademische Studien handeln würde. Vieles von
dem, was hier an Konzepten vorgestellt wird, ist in dieser Form Gegenstand
von experimentellen Implementierungen unserer Arbeitsgruppe an der Technischen Universität Berlin. Und es ist nicht ausgeschlossen, dass daraus eines
Tages auch eine reale Sprache opal-2 wird, mit einem Compiler, den man aus
dem Internet herunterladen kann . . .
VIII
Vorwort
Ein solches Unterfangen wird nicht alleine von zwei Menschen geleistet.
Es tragen im Laufe der Jahre viele dazu bei. An erster Stelle sind hier die
ehemaligen und aktuellen Mitarbeiter unserer Arbeitsgruppe an der TU Berlin zu nennen, insbesondere (in alphabetischer Reihenfolge) Michael Cebulla,
Klaus Didrich, Thomas Frauenstein, Wolfgang Grieskamp, Markus Lepper,
Christian Maeder, Thomas Nitsche, Wolfram Schulte, Mario Südholt, Baltasar Trancon-y-Wideman, Stephan Weber und Jacob Wieland. Sie haben im
Rahmen von Projekten, Doktorarbeiten und Lehrveranstaltungen viel zur Gestaltung der hier diskutierten Konzepte beigetragen. Unserer besonderer Dank
gilt André Metzner für viele fruchtbare Diskussionen, sowie Dirk Reckmann
und Martin Grabmüller, die Teile des Buches kritisch gelesen und durch vielfältige Kommentare verbessert haben. Vor allem aber schulden wir Stephan
Frank großen Dank, der sowohl inhaltlich als auch technisch einen enormen
Beitrag geleistet hat.
Wir hatten aber auch das Vergnügen, mit vielen Kollegen innerhalb und
außerhalb der TU Berlin zahlreiche stimulierende Diskussionen zu führen, aus
denen wichtige Anregungen für dieses Buch hervorgingen. Besonders hervorzuheben sind hier Bernd Mahr von der TU Berlin sowie Doug Smith und Dusko
Pavlovic vom Kestrel Institute. Auch die Diskussionen mit den Kollegen der
IFIP Working Groups 2.1 und 1.3 haben uns viele Einsichten gebracht.
Die Mitarbeiter des Springer-Verlags haben durch ihre kompetente Unterstützung viel zu der jetzigen Gestalt des Buches beigetragen.
Berlin, im März 2006
Peter Pepper
Petra Hofstedt
Inhaltsverzeichnis
Teil I Elementare Funktionale Programmierung
Eine Wiederholung
0
Das
0.1
0.2
0.3
0.4
0.5
Strittigste vorab: Notationen . . . . . . . . . . . . . . . . . . . . . . . . . .
Jenseits von ASCII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Jenseits von Infix: Mixfix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Overloading extrem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Layout mit Bedeutung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Bindung von Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
4
5
6
7
8
1
Grundlagen der Funktionalen Programmierung . . . . . . . . . . . .
1.1 Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.1 Funktionsdefinition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.2 Ausdrücke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.3 λ-Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.4 Funktionalitäten: Die Typisierung von Funktionen . . . . .
1.1.5 Partielle Applikation und Currying . . . . . . . . . . . . . . . . . .
1.1.6 Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.7 Musterbasierte Funktionsdefinition . . . . . . . . . . . . . . . . . .
1.1.8 Erweitertes Patternmatching . . . . . . . . . . . . . . . . . . . . . . . .
1.1.9 Polymorphie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.10 Eigenschaften (Propertys) . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.11 Sequenzen (Listen, Folgen) . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Funktionale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.1 Allgemeine Funktionale . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.2 Catamorphismen (Map-Filter-Reduce) . . . . . . . . . . . . . . .
1.3 Semantik und Auswertungsstrategien . . . . . . . . . . . . . . . . . . . . . .
1.3.1 Denotationelle Semantik . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3.2 Operationale Semantik . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4 Mit Programmen rechnen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.1 Von linearer Rekursion zu Tail-Rekursion . . . . . . . . . . . . .
11
11
12
13
13
15
16
17
18
19
20
21
22
23
24
25
31
31
32
35
35
X
Inhaltsverzeichnis
1.4.2 Ein „universeller Trick“: Continuations . . . . . . . . . . . . . . . 38
1.4.3 Vereinfachung komplexerer Rekursionen . . . . . . . . . . . . . . 41
1.5 OPAL, ML und HASKELL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2
Faulheit währt unendlich . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1 Unendliche Objekte: die Idee . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 lazy, quote und unquote . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.1 lazy als generischer Typ . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.2 Simulation in strikten Sprachen wie OPAL oder ML . . . .
2.3 lazy Listen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4 Programmieren mit lazy Listen . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4.1 Unbeschränkte Folgen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4.2 Approximationsaufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4.3 Animation („Ströme“) . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
47
49
50
50
51
53
53
55
56
3
Parser als Funktionen höherer Ordnung . . . . . . . . . . . . . . . . . . .
3.1 Vorbemerkung zu Grammatiken und Syntaxbäumen . . . . . . . . .
3.2 Parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3 Scanner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.4 Verallgemeinerungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
61
62
65
67
Teil II Strukturierung von Programmen
4
Gruppen: Die Basis der Modularisierung . . . . . . . . . . . . . . . . . .
4.1 Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 Das allgemeine Konzept der Gruppen . . . . . . . . . . . . . . . . . . . . . .
4.2.1 Syntactic sugar: Schlüsselwörter . . . . . . . . . . . . . . . . . . . . .
4.2.2 Selektoren und die Semantik von Gruppen . . . . . . . . . . . .
4.3 Environments und Namensräume . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.1 Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.2 Scopes und lokale Namensräume . . . . . . . . . . . . . . . . . . . .
4.3.3 Namenserkennung im Scope . . . . . . . . . . . . . . . . . . . . . . . .
4.3.4 Namenserkennung außerhalb des Scopes (use) . . . . . . . .
4.4 Overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5 Beispiele für Strukturen und Packages . . . . . . . . . . . . . . . . . . . . .
4.6 Weitere syntaktische Spielereien . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.6.1 Verteilte Definition von Items . . . . . . . . . . . . . . . . . . . . . . .
4.6.2 Tupel als spezielle Gruppen . . . . . . . . . . . . . . . . . . . . . . . . .
4.7 Programme und das Betriebssystem . . . . . . . . . . . . . . . . . . . . . . .
4.7.1 Was ist eigentlich ein Programm? . . . . . . . . . . . . . . . . . . .
4.7.2 . . . und was ist mit den Programmdateien? . . . . . . . . . . .
73
74
74
76
77
79
81
81
82
83
85
86
88
88
90
90
91
92
Inhaltsverzeichnis
5
XI
Operatoren auf Gruppen (Morphismen) . . . . . . . . . . . . . . . . . . . 95
5.1 Vererbung (extend) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
5.2 Signatur-Morphismen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
5.2.1 Restriktion (only, without) . . . . . . . . . . . . . . . . . . . . . . . 97
5.2.2 Renaming (renaming) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5.2.3 Kombination und Verwendung von Morphismen . . . . . . . 98
5.2.4 Vererbung mit Modifikation . . . . . . . . . . . . . . . . . . . . . . . . 99
5.3 Geheimniskrämerei: Import und Export . . . . . . . . . . . . . . . . . . . . 101
5.3.1 Schutzwall nach außen – Export (private, public) . . . . 102
5.3.2 Schutzwall nach innen – Import . . . . . . . . . . . . . . . . . . . . . 103
5.4 Generizität: Funktionen, die Gruppen liefern . . . . . . . . . . . . . . . . 105
Teil III Die Idee der Typisierung
6
Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
6.1 Generelle Aspekte von Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
6.1.1 Die Pragmatik: Statische oder dynamische Typprüfung? 109
6.1.2 Reflection: Typen als „First-class citizens“ . . . . . . . . . . . 111
6.1.3 Intensionalität, Reflection und der Compiler . . . . . . . . . . 113
6.1.4 Typen sind auch nur Terme . . . . . . . . . . . . . . . . . . . . . . . . . 114
6.1.5 Typdeklarationen: Typsynonyme oder neue Typen? . . . . 114
6.1.6 Kinding: Typen höherer Stufe . . . . . . . . . . . . . . . . . . . . . . . 115
6.1.7 Mehrfachtypisierung (Mehrfachvererbung) . . . . . . . . . . . . 116
6.2 Elementare Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
6.3 Aufzählungstypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
6.4 Tupel- und Gruppentyp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
6.4.1 Tupeltyp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
6.4.2 Gruppentyp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
6.5 Summentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
6.5.1 Was für ein Typ bist du? Dieser Typ! . . . . . . . . . . . . . . . . 124
6.5.2 Disjunkt oder nicht? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
6.5.3 Summen mit Typausdrücken . . . . . . . . . . . . . . . . . . . . . . . . 127
6.5.4 Syntactic sugar: Overloading von "‘ : "’ . . . . . . . . . . . . . . . 128
6.6 Funktionstypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
6.7 Rekursive Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
6.8 Wie geht’s weiter? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
7
Subtypen (Vererbung) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
7.1 Ein genereller Rahmen für Subtypen . . . . . . . . . . . . . . . . . . . . . . . 131
7.1.1 Die Subtyp-Relation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
7.1.2 Typanpassung (Casting) . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
7.1.3 Coercion Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
7.2 Direkte Subtypen: Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
7.3 Gruppen/Tupel und Subtypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
XII
Inhaltsverzeichnis
7.3.1 Subtypen von Tupeltypen . . . . . . . . . . . . . . . . . . . . . . . . . . 139
7.3.2 Produkttypen mit Constraints . . . . . . . . . . . . . . . . . . . . . . 139
7.4 Summentypen und Subtypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
7.4.1 Varianten und „echte“ Subtypen . . . . . . . . . . . . . . . . . . . . 141
7.4.2 Summen + Tupel sind ein Schutzwall . . . . . . . . . . . . . . . . 142
7.5 Funktionstypen und Subtypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
8
Polymorphe und abhängige Typen . . . . . . . . . . . . . . . . . . . . . . . . . 145
8.1 Typfunktionen (generische Typen, Polymorphie) . . . . . . . . . . . . . 146
8.1.1 Typvariablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
8.1.2 Typfunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
8.2 Abhängige Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
8.3 Notationen für Typterme mit Variablen . . . . . . . . . . . . . . . . . . . . 154
8.3.1 Bindung von Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
8.3.2 Syntactic sugar: Nachgestellte Variablen . . . . . . . . . . . . . 155
8.3.3 Syntactic sugar: Optionale Parameter . . . . . . . . . . . . . . . . 155
9
Spezifikationen und Typklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
9.1 Operatoren auf Typklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
9.2 Signaturen: Die Typisierung von Strukturen . . . . . . . . . . . . . . . . 162
9.2.1 Syntactic sugar: Traditionelle Signatur-Notation . . . . . . . 163
9.2.2 Syntactic sugar: Verschmelzen von Struktur und
Signatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
9.3 Spezifikationen: Subtypen von Signaturen . . . . . . . . . . . . . . . . . . 165
9.4 Signaturen und Spezifikationen sind existenziell . . . . . . . . . . . . . 167
9.4.1 Zahlen generell betrachtet . . . . . . . . . . . . . . . . . . . . . . . . . . 167
9.4.2 Existenzielle Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
9.5 Von Spezifikationen zu Typklassen . . . . . . . . . . . . . . . . . . . . . . . . . 169
9.5.1 Typklassen à la HASKELL . . . . . . . . . . . . . . . . . . . . . . . . . . 169
9.5.2 Definition von Typklassen . . . . . . . . . . . . . . . . . . . . . . . . . . 170
9.6 Beispiele für Spezifikationen und ihre Typklassen . . . . . . . . . . . . 173
9.6.1 Gleichheit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
9.6.2 Ordnung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
9.6.3 Halbgruppen, Monoide and all that . . . . . . . . . . . . . . . . . . 175
9.6.4 Druckbares, Speicherbares . . . . . . . . . . . . . . . . . . . . . . . . . . 176
9.7 Subklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
9.8 Views und Mehrfachtypisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
9.8.1 Mehrfachtypisierung bei Typklassen . . . . . . . . . . . . . . . . . 178
9.8.2 Views (Mehrfache Sichten) . . . . . . . . . . . . . . . . . . . . . . . . . 179
9.9 Beispiel: Physikalische Dimensionen . . . . . . . . . . . . . . . . . . . . . . . . 184
10 Beispiel: Berechnung von Fixpunkten . . . . . . . . . . . . . . . . . . . . . . 187
10.1 Beispiel: Erreichbarkeit in einem Graphen . . . . . . . . . . . . . . . . . . 187
10.2 Ein bisschen Mathematik: CPOs und Fixpunkte . . . . . . . . . . . . . 189
10.2.1 Vollständige partielle Ordnungen – CPOs . . . . . . . . . . . . . 189
Inhaltsverzeichnis
XIII
10.2.2 Standardkonstruktionen für CPOs . . . . . . . . . . . . . . . . . . . 190
10.2.3 CPO-Konstruktion durch Idealvervollständigung . . . . . . 191
10.2.4 Fixpunkte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
10.3 Die Programmierung von Fixpunkt-Algorithmen . . . . . . . . . . . . . 197
10.3.1 CPOs als Typklasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
10.3.2 Fixpunktberechnung: Der Basisalgorithmus . . . . . . . . . . . 198
10.3.3 Optimierung durch feinere Granularität . . . . . . . . . . . . . . 199
10.3.4 Verallgemeinerungen und Variationen . . . . . . . . . . . . . . . . 201
10.3.5 Fixpunkte als „Design Pattern“ . . . . . . . . . . . . . . . . . . . . . 202
10.4 Datentypen als CPOs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
10.5 Beispiel: Lösung von Gleichungssystemen . . . . . . . . . . . . . . . . . . . 209
10.5.1 Repräsentation von Gleichungssystemen . . . . . . . . . . . . . . 210
10.5.2 Optimierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
10.5.3 Nochmals: Grammatiken und Parser . . . . . . . . . . . . . . . . . 212
10.5.4 Ein Gedankenexperiment: Anpassbare Rekursion . . . . . . 215
11 Beispiel: Monaden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
11.1 Kategorien, Funktoren und Monaden . . . . . . . . . . . . . . . . . . . . . . . 218
11.1.1 Typklassen als Kategorien . . . . . . . . . . . . . . . . . . . . . . . . . . 218
11.1.2 Polymorphe Typen als Funktoren . . . . . . . . . . . . . . . . . . . 219
11.1.3 Monaden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
11.2 Beispiele für Monaden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
11.2.1 Sequenzen als Monaden . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
11.2.2 Maybe als Monade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
11.2.3 Automaten als Monaden („Zustands-Monaden“) . . . . . . . 224
11.2.4 Spezielle Zustands-Monaden . . . . . . . . . . . . . . . . . . . . . . . . 227
11.2.5 Zähler als Zustands-Monaden . . . . . . . . . . . . . . . . . . . . . . . 230
11.2.6 Generatoren als Zustands-Monaden . . . . . . . . . . . . . . . . . . 231
11.2.7 Ein-/Ausgabe als Zustands-Monade . . . . . . . . . . . . . . . . . . 231
11.3 Spezielle Notationen für Monaden . . . . . . . . . . . . . . . . . . . . . . . . . 231
11.3.1 Die Operatoren „→“ und „ ; “ . . . . . . . . . . . . . . . . . . . . . . . 232
11.3.2 Erweitertes let . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
11.3.3 Monaden-Casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
Teil IV Datenstrukturen
12 Netter Stack und böse Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
12.1 Wenn Listen nur anders heißen: Stack . . . . . . . . . . . . . . . . . . . . . . 241
12.2 Wenn Listen zum Problem werden: Queue . . . . . . . . . . . . . . . . . . 242
12.2.1 Variante 1: Queue = Paar von Listen . . . . . . . . . . . . . . . . 243
12.2.2 Variante 2: Faulheit macht kalkulierbar . . . . . . . . . . . . . . 245
12.3 Deque und Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
12.3.1 Double-ended Queues (Deque) . . . . . . . . . . . . . . . . . . . . . . 249
12.3.2 Sequenzen (Catenable Lists) . . . . . . . . . . . . . . . . . . . . . . . . 250
XIV
Inhaltsverzeichnis
12.4 Arbeiten mit listenartigen Strukturen . . . . . . . . . . . . . . . . . . . . . . 252
13 Compilertechniken für funktionale Datenstrukturen . . . . . . . 255
13.1 Die Bedeutung von Single-Threadedness . . . . . . . . . . . . . . . . . . . . 256
13.1.1 Die Analyse von Single-Threadedness . . . . . . . . . . . . . . . . 257
13.1.2 Monaden garantieren Single-Threadedness . . . . . . . . . . . . 259
13.1.3 Lineare Typen garantieren Single-Threadedness . . . . . . . 261
13.2 A Dag For All Heaps (Reference-Counting) . . . . . . . . . . . . . . . . . 263
13.2.1 Ein Dag-Modell für das Datenmanagement . . . . . . . . . . . 263
13.2.2 Sicheres Management persistenter Strukturen . . . . . . . . . 268
13.2.3 Dynamische Erkennung von Single-Threadedness . . . . . . 273
13.2.4 „Tail-Rekursion modulo cons“ . . . . . . . . . . . . . . . . . . . . . . . 275
13.2.5 Reference-Counting und Queues: Hilft Laziness? . . . . . . . 280
13.3 Version Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
14 Funktionale Arrays und Numerische Mathematik . . . . . . . . . . 287
14.1 Semantik von Arrays: Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . 288
14.1.1 Die Typklasse der Intervalle . . . . . . . . . . . . . . . . . . . . . . . . 288
14.1.2 Eindimensionale Arrays (Vektoren) . . . . . . . . . . . . . . . . . . 290
14.1.3 Mehrdimensionale Arrays (Matrizen) . . . . . . . . . . . . . . . . 293
14.1.4 Matrizen von besonderer Gestalt (Shapes) . . . . . . . . . . . . 294
14.1.5 Map-Reduce auf Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
14.2 Pragmatik von Arrays: „Eingefrorene“ Funktionen . . . . . . . . . . . 297
14.2.1 Memoization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
14.2.2 Speicherblöcke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
14.2.3 Sicherheit und Single-Threadedness: Version Arrays . . . . 301
14.2.4 Von Arrays zu Speicherblöcken . . . . . . . . . . . . . . . . . . . . . . 301
14.2.5 Implementierung eindimensionaler Arrays . . . . . . . . . . . . 302
14.2.6 Implementierung mehrdimensionaler Arrays . . . . . . . . . . 303
14.3 Arrays in der Numerik: Vektoren und Matrizen . . . . . . . . . . . . . . 304
14.3.1 Vektoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
14.3.2 Matrizen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
14.4 Beispiel: Gauß-Elimination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
14.4.1 Lösung von Dreieckssystemen . . . . . . . . . . . . . . . . . . . . . . . 307
14.4.2 LU -Zerlegung (Doolittle-Variante) . . . . . . . . . . . . . . . . . . . 309
14.4.3 Spezialfall: Gauß-Elimination bei Tridiagonalmatrizen . . 311
14.5 Beispiel: Interpolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
14.6 Beispiel: Spline-Interpolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
14.7 Beispiel: Schnelle Fourier-Transformation (FFT) . . . . . . . . . . . . . 318
15 Map: Wenn Funktionen zu Daten werden . . . . . . . . . . . . . . . . . . 323
15.1 Variationen über Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
15.2 Die Typklasse der Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
15.3 Die Typklasse der Mappings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
15.3.1 Implementierungen von Maps . . . . . . . . . . . . . . . . . . . . . . . 329
Inhaltsverzeichnis
XV
15.3.2 Map-Filter-Reduce auf Maps . . . . . . . . . . . . . . . . . . . . . . . . 329
15.3.3 Prädikate höherer Ordnung auf Maps . . . . . . . . . . . . . . . . 331
15.4 Maps und Funktionen: Zwei Seiten einer Medaille . . . . . . . . . . . . 333
15.5 Maps, Funktionen und Memoization . . . . . . . . . . . . . . . . . . . . . . . 334
16 Beispiel: Synthese von Programmen . . . . . . . . . . . . . . . . . . . . . . . 337
16.1 Globale Suche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
16.1.1 Suchräume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
16.1.2 Einschränkung von Suchräumen . . . . . . . . . . . . . . . . . . . . . 339
16.1.3 Suchräume und partielle Lösungen . . . . . . . . . . . . . . . . . . . 340
16.1.4 Basisregeln für Suchräume . . . . . . . . . . . . . . . . . . . . . . . . . . 340
16.2 Problemlösungen als Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
16.2.1 Beispiel: Das n-Damen-Problem . . . . . . . . . . . . . . . . . . . . . 341
16.2.2 Suchräume als Mengen von Maps . . . . . . . . . . . . . . . . . . . . 343
16.2.3 Constraints auf Mengen von Maps . . . . . . . . . . . . . . . . . . . 344
16.3 Programmableitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
16.3.1 Das n-Damen-Problem – Von der Spezifikation zum
Algorithmus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
16.3.2 Ein allgemeines Schema für die globale Suche . . . . . . . . . 350
16.4 Beispiel: Scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
Teil V Integration von Paradigmen
17 Zeit und Zustand in der funktionalen Welt . . . . . . . . . . . . . . . . 359
17.1 Zeit und Zustand: Zwei Seiten einer Medaille . . . . . . . . . . . . . . . . 360
17.1.1 Ein kleines Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
17.2 Monaden: Ein schicker Name für Altbekanntes . . . . . . . . . . . . . . 364
17.2.1 Programmieren mit Continuations . . . . . . . . . . . . . . . . . . . 366
17.2.2 Continuations + Hiding = Monaden . . . . . . . . . . . . . . . . . 368
17.2.3 Die Ein-/Ausgabe ist eine Compiler-interne Monade . . . 369
17.3 Zeit: Die elementarste aller Zustands-Monaden . . . . . . . . . . . . . . 369
17.3.1 Zeitabhängige Operationen und Evolution . . . . . . . . . . . . 371
17.3.2 Zeit-Monade oder Zustands-Monade? . . . . . . . . . . . . . . . . 374
17.4 Die erweiterte Zeit-Monade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
17.4.1 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
17.4.2 Choice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
17.4.3 Die Systemuhr und Timeouts . . . . . . . . . . . . . . . . . . . . . . . 378
17.4.4 Zusammenfassung: Die Zeit-Monade . . . . . . . . . . . . . . . . . 378
18 Objekte und Ein-/Ausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
18.1 Objekte als zeitabhängige Werte . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
18.1.1 Spezielle Notationen für Objekte und Klassen . . . . . . . . . 385
18.1.2 „Globale“ Objekte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
18.2 Laufzeitsystem und andere Objekte (Zeit-Monaden) . . . . . . . . . 389
XVI
Inhaltsverzeichnis
18.2.1 Dateioperationen höherer Ordnung . . . . . . . . . . . . . . . . . . 392
18.2.2 Ein typisiertes Dateisystem? . . . . . . . . . . . . . . . . . . . . . . . . 393
19 Agenten und Prozesse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
19.1 Service-orientierte Architekturen . . . . . . . . . . . . . . . . . . . . . . . . . . 396
19.2 Agenten als Monaden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
19.3 Kommunikation: Service-Access-Points . . . . . . . . . . . . . . . . . . . . . 400
19.4 Ein Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
19.5 „Globale“ Agenten und SAPs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
19.6 Spezialfälle: Kanäle und Gates . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
19.6.1 Kanäle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
19.6.2 Gates: SAPs + Agenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
19.7 OPAL, CONCURRENT HASKELL, EDEN und ERLANG . . . . . . 418
20 Graphische Schnittstellen (GUIs) . . . . . . . . . . . . . . . . . . . . . . . . . . 421
20.1 GUIs – ein Konzept mit drei Dimensionen . . . . . . . . . . . . . . . . . . 422
20.2 Die Applikation (Model) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
20.3 Graphische Gestaltung (View) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
20.3.1 Arten von GUI-Elementen . . . . . . . . . . . . . . . . . . . . . . . . . . 427
20.3.2 Stil-Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
20.3.3 Geometrische Anordnung . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
20.3.4 The Big Picture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
20.4 Interaktion mit der Applikation (Control) . . . . . . . . . . . . . . . . . . 434
20.4.1 Das Fenster als Agent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
20.4.2 Emitter als Kanäle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
20.4.3 Regulator-Gates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
20.4.4 Weitere Gates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
20.4.5 Ereignisse – Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
20.5 HAGGIS, FUDGETS, FRANTK und andere . . . . . . . . . . . . . . . . . . 441
21 Massiv parallele Programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
21.1 Skeletons: Parallelität durch spezielle Funktionale . . . . . . . . . . . 444
21.2 Cover: Aufteilung des Datenraums . . . . . . . . . . . . . . . . . . . . . . . . . 446
21.2.1 Spezifikation von Covern . . . . . . . . . . . . . . . . . . . . . . . . . . . 447
21.2.2 Skelette über Covern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
21.2.3 Matrix-Cover . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
21.3 Beispiel: Matrixmultiplikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452
21.4 Von Skeletons zum Message passing . . . . . . . . . . . . . . . . . . . . . . . 456
22 Integration von Konzepten anderer
Programmierparadigmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
22.1 Programmierparadigmen und deren Integration . . . . . . . . . . . . . 459
22.2 Objektorientierte Erweiterungen funktionaler Sprachen . . . . . . . 461
22.2.1 HASKELL++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
22.2.2 O’HASKELL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
Inhaltsverzeichnis
XVII
22.2.3 OCAML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464
22.3 Funktional-logische Programmierung und darüber hinaus . . . . . 464
22.4 Fazit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467
Literatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479
Hinweis: Eine Errata-Liste und weitere Hinweise zu diesem Buch sind über die
Web-Adresse http://www.uebb.cs.tu-berlin.de/books/fp zu erreichen.
Teil I
Elementare Funktionale Programmierung
Eine Wiederholung
Wer Fortgeschrittenes diskutieren will, muss sich erst einmal über das Elementare im Klaren sein. Das gilt für Programmierkonzepte genauso wie für
alle anderen Betätigungen.
Es gibt eine Fülle von einführenden Büchern zum Thema „Funktionale
Programmierung“, unter anderem [20, 22, 32, 47, 50, 81, 102, 111, 122]. Diese
Auswahl von Büchern aus den letzten fünfzehn Jahren zeigt, dass das Thema
eine stetige Weiterentwicklung erfahren hat, aber auch, dass es Sackgassen
gegeben hat.
Wir werden uns primär mit neueren Konzepten befassen, teilweise mit
bereits anerkannten und etablierten, teilweise aber auch mit hochgradig experimentellen. Dabei gehen wir davon aus, dass dem Leser die elementaren
Grundkonzepte der Funktionalen Programmierung, wie sie in den obigen Büchern beschrieben werden, bereits bekannt sind.
Um einen wohldefinierten Aufsetzpunkt zu haben, beginnen wir mit einem
kurzen Rückblick auf die elementaren Grundlagen der Funktionalen Programmierung und vor allem mit einigen Vereinbarungen zur Notation, die wir im
Folgenden verwenden. In unserer Darstellung orientieren wir uns primär an
[111], aber auch an [81] oder [20] – ohne allerdings die dortigen Schreibweisen
komplett zu übernehmen.
0
Das Strittigste vorab: Notationen
Über Geschmack lässt sich nicht
streiten.
(Sprichwort)
Natürlich lässt sich – entgegen anderslautenden Sprichwörtern – über Geschmack ganz trefflich streiten. Einer Anekdote zufolge sollen sich einst international hochreputierte Professoren wütend über die Frage gezankt haben, ob
man eine Integervariable mittels int x oder x : int einführen sollte. Die erste
Variante orientiert sich an der umgangssprachlichen Formulierung „die Integervariable x“ und hat von algol aus ihren Weg z. B. in c, c++ und von da
aus weiter in java gefunden. Die zweite Variante orientiert sich an der mathematischen Notation x ∈ Int und drang von pascal aus z. B. in modula
und ada vor.
Die Erkenntnis, dass ein solcher Streit wohl müßig ist, hat zu einer Gegenbewegung geführt, die Notation für völlig belanglos erklärte und ausschließlich
über Konzepte sprach. Doch beweist die Zahl der gescheiterten Sprachen, die
exzellente Konzepte mit völlig unlesbarer Syntax verbanden, dass Notation
eben doch nicht ganz vernachlässigbar ist.
In der Quintessenz hat sich die Erkenntnis durchgesetzt, dass eine Sprache zwar primär an ihren Konzepten zu messen ist, dass sie diese aber in
brauchbaren Notationen vermitteln muss.
Ein Buch, das sich modernes Sprachdesign zum Thema gesetzt hat, darf
deshalb das Thema Notationen nicht ignorieren. Und modern heißt heute auch, dass man die Standards übernehmen muss, die von graphischen
Bildschirm- und Drucksystemen sowie von Setzwerkzeugen wie TEX und Postscript vorgegeben wurden. Das führt zu einer Sicht auf Notationen, die von
gängigen Mustern bei Programmiersprachen radikal abweicht.
4
0 Das Strittigste vorab: Notationen
0.1 Jenseits von ASCII
Die Designer von Programmiersprachen scheinen eine merkwürdige Affinität
zu den guten alten ascii-Terminals zu haben. Anders ist es kaum zu erklären,
dass die größte notationelle Revolution der letzten dreißig Jahre das Zulassen
von unicode-Zeichen in java war. Dabei gibt es spätestens seit den Zeiten
von TEX und mathematica keinen Grund mehr, an dieser Beschränkung
festzuhalten. Und wer jemals einen Kollegen in China beobachtet hat, wie er
seitenweise chinesischen Text aus einem ascii-Terminal zaubert, muss zugeben, dass die Konformität zwischen Input und lesbarem Output auch nur ein
vorgeschobenes Argument ist.
Mathematische Notation
Vor diesem Hintergrund machen sich einige Informatiker wie z. B. Guy Steele
von der Firma SUN inzwischen dafür stark, die Schreibweisen von Programmiersprachen radikal zu modernisieren. Es gibt schließlich keinen Grund, weshalb Programme so viel altmodischer aussehen müssen als Mathematik. Tabelle 0.1 zeigt, dass derselbe Programmtext in ganz verschiedenen Notationen
dargestellt werden kann.
ascii
unicode
TEX
rho0 = r DOT r
ρ0 = r · r
ρ0 = r · r
v
v norm = v / ||v||
P
[k=1:n] a[k] x k
v
vnorm = v
Pn
k
k=1 ak x
norm = v / norm v
SUM[k=1:n] a[k] x
k
Tab. 0.1: Verschiedene Schreibweisen eines Programmfragments (nach G. Steele)
Wir werden uns in diesem Buch weitestgehend an die dritte – also die
fortschrittlichste – dieser Varianten halten.
Fonts
Neben mathematischen Zeichen bieten moderne Textsysteme auch die Möglichkeit, mit unterschiedlichen Fonts zu arbeiten. Allerdings besteht dabei die
Gefahr, zu viel des Guten zu tun und ein extrem unruhiges Satzbild zu erzeugen. Wir suchen hier einen Kompromiss und verwenden die Fonts und
Konventionen aus Tabelle 0.2.
Namen von Werten, Funktionen etc. schreiben wir (meist) klein und –
mathematischer Tradition folgend – kursiv. Wie auch bei allen anderen Symbolen erlauben wir Indizierung ebenso wie Annotation mit Strichen. Typen
und Strukturen werden ebenfalls kursiv geschrieben, allerdings beginnend mit
einem Großbuchstaben. Für Typklassen verwenden wir einen speziellen Font.
Herunterladen