Funktionale Programmierung mit Haskell



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

Vorkurs C++ Programmierung

Zeichen bei Zahlen entschlüsseln

Funktionale Programmierung

Java Kurs für Anfänger Einheit 5 Methoden

Programmierkurs Java

DieÜbersetzung funktionaler Programmiersprachen

Technische Informatik 1 Übung 2 Assembler (Rechenübung) Georgia Giannopoulou (ggeorgia@tik.ee.ethz.ch) 22./23. Oktober 2015

Grundbegriffe der Informatik

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!.

Zwischenablage (Bilder, Texte,...)

5 DATEN Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu

Einführung in die Java- Programmierung

Java Virtual Machine (JVM) Bytecode

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Erwin Grüner

Zählen von Objekten einer bestimmten Klasse

Objektorientierte Programmierung

Grundlagen der Informatik. Prof. Dr. Stefan Enderle NTA Isny

Adressen. Praktikum Funktionale Programmierung Organisation und Überblick. Termine. Studienleistung

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Algorithmen und Datenstrukturen

Applet Firewall und Freigabe der Objekte

AGROPLUS Buchhaltung. Daten-Server und Sicherheitskopie. Version vom b

BEISPIELKLAUSUR Softwareentwicklung:

Constraint-Algorithmen in Kürze - Mit der Lösung zur Path-Consistency-Aufgabe 9

Grundlagen der Programmierung (Vorlesung 14)

1 Vom Problem zum Programm

4. AUSSAGENLOGIK: SYNTAX. Der Unterschied zwischen Objektsprache und Metasprache lässt sich folgendermaßen charakterisieren:

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

Einführung in die Java- Programmierung

Unterprogramme. Funktionen. Bedeutung von Funktionen in C++ Definition einer Funktion. Definition einer Prozedur

Theoretische Grundlagen der Informatik

VBA-Programmierung: Zusammenfassung

1. IPSec Verbindung zwischen 2 Gateways mit dynamischen IP Adressen

Folgende Voraussetzungen für die Konfiguration müssen erfüllt sein: - Ein Bootimage ab Version Optional einen DHCP Server.

Excel Funktionen durch eigene Funktionen erweitern.

Funktionale Programmierung. Funktionale Programmierung: Vorlesungsüberblick. Eigenschaften rein funktionaler Programmierung

Informatik 1 Tutorial

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

Einführung in die Programmierung

Professionelle Seminare im Bereich MS-Office

ARCO Software - Anleitung zur Umstellung der MWSt

Anleitung Typo3-Extension - Raumbuchungssystem

Programmierung für Mathematik (HS13)

Wie halte ich Ordnung auf meiner Festplatte?

Beweisbar sichere Verschlüsselung

C++ Grundlagen. ++ bedeutet Erweiterung zum Ansi C Standard. Hier wird eine Funktion eingeleitet

AZK 1- Freistil. Der Dialog "Arbeitszeitkonten" Grundsätzliches zum Dialog "Arbeitszeitkonten"

5.2 Neue Projekte erstellen

Matrix42. Use Case - Sicherung und Rücksicherung persönlicher Einstellungen über Personal Backup. Version September

Diese Ansicht erhalten Sie nach der erfolgreichen Anmeldung bei Wordpress.

Über Arrays und verkettete Listen Listen in Delphi

Übungsblatt 3: Algorithmen in Java & Grammatiken

Einführung in die Algebra

Programmierung 2. Übersetzer: Code-Erzeugung. Sebastian Hack. Klaas Boesche. Sommersemester

Automatisches Parallelisieren

Univariates Chi-Quadrat-Verfahren für ein dichotomes Merkmal und eine Messwiederholung: Test nach McNemar

Verbesserungsdetails: PTC Mathcad Prime 3.0. Copyright 2013 Parametric Technology Corporation. weiter Infos unter

Access Grundlagen für Anwender. Susanne Weber. 1. Ausgabe, 1. Aktualisierung, Juni 2013

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

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Hochschule Ravensburg-Weingarten. Technik Wirtschaft Sozialwesen. Projektarbeit

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Installation von Microsoft Visual C Express

Kurzeinführung LABTALK

Speicher in der Cloud

Funktionale Programmierung mit Haskell

Handbuch für Redakteure

Arge Betriebsinformatik GmbH & Co.KG, CAP News 40, Februar CAP-News 40

Stand: Adressnummern ändern Modulbeschreibung

Objektorientierte Programmierung. Kapitel 12: Interfaces

WINDOWS 10 Upgrade. Beispiel: Desktop-Ausschnitt von vorhandenem WIN 8.1 (rechte Ecke der Taskleiste)

2. Semester, 2. Prüfung, Lösung

Switching. Übung 7 Spanning Tree. 7.1 Szenario

Algorithmische Kryptographie

Prozedurale Datenbank- Anwendungsprogrammierung

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Hilfe Bearbeitung von Rahmenleistungsverzeichnissen

Statuten in leichter Sprache

Dokumentation: Balanced Scorecard

Übungen zu C++ Kapitel 1

Wir arbeiten mit Zufallszahlen

Programmieren. 10. Tutorium 4./ 5. Übungsblatt Referenzen

Anleitung: Einrichtung der Fritz!Box 7272 mit VoIP Telefonanschluss

E-PRIME TUTORIUM Die Programmiersprache BASIC

Erstellen einer digitalen Signatur für Adobe-Formulare

Zertifikat in dakota einlesen Wie lese ich mein Zertifikat in dakota.le ein?

Systeme 1. Kapitel 6. Nebenläufigkeit und wechselseitiger Ausschluss

5. Tutorium zu Programmieren

BEDIENUNG ABADISCOVER

Datensicherung. Beschreibung der Datensicherung

Windows 8.1. Grundkurs kompakt. Markus Krimm, Peter Wies 1. Ausgabe, Januar inkl. zusätzlichem Übungsanhang K-W81-G-UA

Modellierung und Programmierung 1

Was ist Sozial-Raum-Orientierung?

Anlegen eines Speicherbereichs mit DB, DW eleganter in Kombination mit EQU, Timer-Interrupt

Bedienungsanleitung. Stand: Copyright 2011 by GEVITAS GmbH

Wie wird ein Jahreswechsel (vorläufig und endgültig) ausgeführt?

Die Gleichung A x = a hat für A 0 die eindeutig bestimmte Lösung. Für A=0 und a 0 existiert keine Lösung.

Einführung in die Programmierung

Transkript:

Funktionale Programmierung mit Haskell Prof Dr Hans J Schneider Lehrstuhl für Programmiersprachen und Programmiermethodik Friedrich-Alexander-Universität Erlangen-Nürnberg Sommersemester 2005 I Die Sprache Haskell II Ergänzungen 7 Kontextfreie Grammatiken 8 Syntaxanalyse 9 Algebraische Spezifikation 10 Semantik von Programmiersprachen 11 Compilieren funktionaler Programme 12 Ausblick: Kategorien c Hans J Schneider 2005

P-Maschine Abstraktes Modell einer Rechenanlage Von N Wirth entwickelt, um die Implementierung von Pascal portabel zu machen Aufbau: Programmspeicher CD mit einem Programmzähler PC Stapelspeicher ST mit dem Zeiger SP Haldenspeicher mit Zeiger NP Befehlsvorrat: bedingte und unbedingte Sprungbefehle Verknüpfungsbefehle, die nur auf dem Stapel arbeiten Transportbefehle von und zum Stapel, wobei sich hinter dem normalen Speicher tiefer liegende Teile des Stapels verbergen (siehe Blockstruktur) compilertechnische Makrobefehle Funktionale Programmierung mit Haskell 111

P-Maschine: Programmabarbeitung Befehlszyklus: PC := 0; do PC := PC + 1; Execute(CD[PC-1]) od Die Reihenfolge innerhalb der Schleife ist Konsequenz der Sprungbefehle und der Unterprogrammaufrufe Auch die teilweise äußerst komplexen compilertechnischen Makrobefehle der P-Maschine werden hier als ein Befehl betrachtet Beispiele von P-Code-Befehlen: P -Code Bedeutung ADD ST [SP 1] := ST [SP 1] + ST [SP ] SP := SP 1 LDC q SP := SP + 1 ST [SP ] := q IND ST [SP ] := ST [ST [SP ]] Funktionale Programmierung mit Haskell 112

Haldenobjekte Speicher der P-Maschine: Stapel Halde SP EP NP Generierung von Haldenobjekten: code(new(x), ρ) = LDC LDC NEW ρ(x) size(type(x)) Konkretisierung des NEW-Befehles: P -Code Bedeutung NEW if NP ST [SP ] EP then error else NP := NP ST [SP ] ST [ST [SP 1]] := NP SP := SP 2 EP = extreme stack pointer Funktionale Programmierung mit Haskell 113

Speicheraufteilung bei Prozeduren Jede Inkarnation einer Prozedur schafft sich eine eigene Umgebung, dh einen eigenen Abschnitt auf dem Stapel: Stapel Halde neue Prozinkarn SP = MP new SP new NP Organisatorische Angaben (Activation record): Rücksprungadresse, ggf Funktionswert (oder dessen Adresse auf der Halde) bisheriger Stapelzeiger bisheriger Wert von EP (muss nach Rückkehr wieder bekannt sein) Beginn des Stapelbereichs der aufrufenden Prozedur (dynamischer Vorgänger) Beginn des Stapelbereichs der syntaktisch umgebenden Prozedur (statischer Vorgänger) Funktionale Programmierung mit Haskell 114

Inkarnationsbeschreibung einer Prozedur Eine mögliche Reihenfolge der Daten: SP + 1 : MP function value SP + 2 : static link (SL) SP + 3 : dynamic link (DL) SP + 4 : extreme pointer (EP ) SP + 5 : return address (RA) SP + 6 : parameters local variables, array descriptors arrays (parameters, local) SP new local stack EP Funktionale Programmierung mit Haskell 115

Aufbau der Inkarnationsbeschreibung Vom aufrufenden Programm zu bearbeiten: Bestimme SL für das gerufene Programm M P des rufenden Programms wird DL des gerufenen Rette EP des rufenden Programms Berechne und speichere aktuelle Parameter Setze M P für das gerufene Programm (ursprüngliches SP + 1) Speichere Rücksprungadresse Springe Prozedur an Vom gerufenen Programm zu bearbeiten: Erhöhe SP um den statischen Speicherbedarf Bearbeite den dynamischen Speicherbedarf Setze neues EP Führe den Prozedurrumpf aus Funktionale Programmierung mit Haskell 116

Übersetzungskontexte bei funktionalen Sprachen Beispiel: letrec add == λx y x + y; dbl == λx x 2; inc == add 1; from == λn cons n (from (inc n)); h == λx if x = 0 then inc else dbl; g == λy h 1 y B: Das Ergebnis ist eine Basiskonstante auf dem Stapel V: Beliebiges Ergebnisobjekt auf der Halde Ein Zeiger auf das Objekt befindet sich auf dem Stapel Beispiele: Vektor von Parametern C: Das Ergebnis ist eine suspendierte Berechnung auf der Halde (closure) Ein Zeiger darauf befindet sich auf dem Stapel Beispiele: die aktuellen Parameter (lazy evaluation) und alle rechten Seiten von Definitionen P: Spezialfall von V für ein gesamtes Programm Funktionale Programmierung mit Haskell 117

Currying Currying konstruiert aus bereits definierten Funktionen neue, indem einige Parameterpositionen frei bleiben Beispiel: letrec add == λx y x + y; inc == add 1; in inc 5; In der Definition von inc wird der erste Parameter von add festgelegt, der zweite bleibt offen Bei der Verwendung von inc wird (compilertechnisch) der zweite Parameter von add festgelegt Der Compiler hat dafür Sorge zu tragen, dass der auszuführende Prozedurrumpf genau die Parameter bekommt, die er benötigt Auf der Halde muss ein Objekt geschaffen werden, das den Zusammenhang zwischen der neu definierten Funktion, dem ursprünglichen Prozedurrumpf und den bereits vorhandenen Parametern herstellt Funktionale Programmierung mit Haskell 118

Funktionen als Ergebnis von Funktionen Eine Funktion kann scheinbar zuviele Parameter haben: Beispiel: letrec in h == λx if x = 0 then inc else dbl; g == λy h 1 y h benötigt einen Parameter, hat aber scheinbar zwei h 1 liefert als Ergebnis eine Funktion, die ihrerseits einen Parameter, hier y, benötigt Das Beispiel legt nahe, die Parameter beim Prozeduraufruf in umgekehrter Reihenfolge auf den Stapel zu legen Funktionale Programmierung mit Haskell 119

Stapelaufbau Der Stapel ist die zentrale Umschlagstation Auf dem Stapel befinden sich Basiskonstanten, Halden- und Stapeladressen, Programmspeicheradressen, zb Adressen von Prozedurrümpfen Stapelabschnitt für eine Funktionsanwendung: SP + 1 : continuation address SP + 2 : F P old (frame pointer) SP + 3 : F P GP old (global pointer) parameters local variables SP new frame pointer entspricht dem dynamic link Der global pointer zeigt auf einen auf der Halde liegenden Vektor, der aus Zeigern auf alle global definierten Objekte besteht Stapelabschnitt für eine Closure-Anwendung: analog, jedoch ohne Parameter Funktionale Programmierung mit Haskell 1110

Haldenobjekte CLOSU RE : (cp, gp): Repräsentiert eine ausstehende Berechnung cp = Zeiger auf den Programmcode (Fortsetzungsadresse) gp = Zeiger auf den Vektor der globalen Objekte F U N V AL : (cf, f ap, f gp): Ergebnis der Definition einer Funktion oder funktionales Ergebnis einer Funktionsanwendung cf = Zeiger auf den Programmcode (Rumpf) fap = Zeiger auf den Vektor der aktuellen Parameter (bei Curry-Funktionen nur teilweise gefüllt) fgp = Zeiger auf den Vektor der globalen Objekte BASIC: Basiskonstante Tritt als Ergebnis von Closure-Anwendungen auf Kann nach Typ weiter differenziert werden V ECT OR: Vektor von Zeigern auf andere (meist: Halden-) Objekte (zb aktuelle Parameter, globale Objekte) Funktionale Programmierung mit Haskell 1111

Beispiel (I) g == λx y x + y + a f == g 1 g F UN : cf fap fgp org( ) eval(par1) eval(par2) ADD eval(a) ADD org / a / ** org enthält ua den Test, ob genügend Argumente vorhanden sind, und erzeugt im andern Fall ein neues F U N V AL-Objekt mit teilweise ausgefülltem fap Funktionale Programmierung mit Haskell 1112

Beispiel (II) g == λx y x + y + a f == g 1 f CLOS : cp gp org eval(1) eval(g) apply org g / apply muss P C, F P, GP aus dem F UNV AL-Objekt g übernehmen und Zeiger auf die (bei Curry-Funktionen) bereits vorhandenen Parameter auf den Stapel kopieren Funktionale Programmierung mit Haskell 1113

Kreierung der Haldenobjekte F UNV AL: bei der Verarbeitung einer Funktionsdefinition CLOSURE: Funktionsrumpf: bei Verarbeitung der rechten Seite einer Definitionsgleichung aktuelle Parameter: bei Verarbeitung einer Funktionsanwendung V ECT OR, BASIC: bei Bedarf Die Kreierung erfolgt an Hand der obersten Stapelobjekte Beispiel: P -Code Bedeutung mkclosure ST [SP 1] := new ( CLOS : ST [SP ], ST [SP 1], ) SP := SP 1 Funktionale Programmierung mit Haskell 1114

Generierung des Zielcodes abhängig vom Kontext Vier Kontexttypen entsprechen vier verschiedenen Prozeduren: P code : B code : V code : C code : Ergebnis = auszuführendes Programm P code(e) = V code(e, [ ], 0) Basiswert auf Stapel Basiswert oder Vektor auf Halde und Zeiger auf Stapel Closure auf Halde und Zeiger auf Stapel Gemeinsame Parameter dieser Prozeduren: e β sl expression to be compiled environment stack level sl ist die Differenz zwischen SP und einem sp 0, das den Anfang der formalen Parameter und lokalen Variablen kennzeichnet β liefert (LOC, reladdr) bzw (GLOB, reladdr) Funktionale Programmierung mit Haskell 1115

Adressierung der Parameter Beispiel letrec f == λv 1 v n letrec a 1 == e 1 ; a q == e q in e 0 ; g == f e 1 e m (m < n) in g e m+1 e k (k > n) Denkbare Lösung (Beispiel beim Aufruf von f mit m = n): P C old F P old F P GP old e n Argumente e 1 sp 0 a 1 lokale Größen a 2 SP a q Funktionale Programmierung mit Haskell 1116

B-Code: Basiskonstante auf Stapel Basiskonstante: B code(b, β, sl) = SP := SP + 1 ST [SP ] := b Ausdruck: B code(e 1 op e 2, β, sl) = B code(e 1, β, sl) B code(e 2, β, sl + 1) op Bedingter Ausdruck: B code(if e 1 then e 2 else e 3, β, sl) = B code(e 1, β, sl) F JP L 1 B code(e 2, β, sl) UJP L 2 L 1 : B code(e 3, β, sl) L 2 : Funktionale Programmierung mit Haskell 1117

V-Code: Basiskonstante oder Vektor auf Halde Basiskonstante: V code(b, β, sl) = B code(b, β, sl) ST [SP ] := new(basic : ST [SP ]) Ausdruck: V code(e 1 op e 2, β, sl) = B code(e 1 op e 2, β, sl) ST [SP ] := new(basic : ST [SP ]) Bedingter Ausdruck: V code(if e 1 then e 2 else e 3, β, sl) = B code(e 1, β, sl) F JP L 1 V code(e 2, β, sl) UJP L 2 L 1 : V code(e 3, β, sl) L 2 : Funktionale Programmierung mit Haskell 1118

Auswertung der Parameter im Kontext C code: C code(v, β, sl) = getvar(v, β, sl) da sowohl die Definitionen der lokalen Größen als auch die aktuellen Parameter zunächst Closure-Objekte sind im Kontext V code: V code(v, β, sl) = getvar(v, β, sl) eval im Kontext B code: B code(v, β, sl) = V code(v, β, sl) if HP [ST [SP ]]tag BASIC then error else ST [SP ] := HP [ST [SP ]] Funktionale Programmierung mit Haskell 1119

Getvar und Eval getvar liefert den Zeiger auf das Objekt: getvar(v, β, sl) = let (p, i) = β(v) in SP := SP + 1 if p = LOC then ST [SP ] := ST [sp 0 + i] else ST [SP ] := HP [GP ]v[i] eval muss nur etwas tun, wenn eine Closure vorliegt, was aber (abgesehen von möglichen Optimierungssituationen) der Normalfall ist: if HP [ST [SP ]]tag = CLOS then ST [SP + 1] := P C ST [SP + 2] := F P ST [SP + 3] := GP GP := HP [ST [SP ]]gp P C := HP [ST [SP ]]cp SP := SP + 3 F P := SP Beachte: Das ist ein Befehl! Funktionale Programmierung mit Haskell 1120

Funktionsdefinition (Lambda-Ausdruck) F UN : cf fap fgp address / globals C code(λv 1 v 2 v n e, β, sl) = getvar(v 1, β, sl) get globals getvar(v g, β, sl + g 1) mkvec g mkvec 0 push L 1 mkf unval UJP L 2 L 1 : targ n test arguments V code(e, [v i (LOC, i), v j (GLOB, j)], 0) return n update stack, repeat application L 2 : Funktionale Programmierung mit Haskell 1121

Funktionsanwendung Voraussetzung: e e e V code(e e 1 e n, β, sl) = ST [SP + 1] := L - - Fortsetzungsadresse ST [SP + 2] := F P ST [SP + 3] := GP SP := SP + 3 F P := SP C code(e n, β, sl + 3) C code(e 1, β, sl + n + 2) V code(e, β, sl + n + 3) apply L : apply muss P C, F P, GP aus dem F UNV AL-Objekt e übernehmen und Zeiger auf die (bei Curry-Funktionen) bereits vorhandenen Parameter auf den Stapel kopieren Funktionale Programmierung mit Haskell 1122

Apply apply muss P C, F P, GP aus dem F UNV AL-Objekt e übernehmen und Zeiger auf die (bei Curry-Funktionen) bereits vorhandenen Parameter auf den Stapel kopieren Stapelstruktur: vor apply nach apply P C old P C old F P old F P old F P GP old F P GP old e n e n e 1 e 1 SP e a p SP a 1 Funktionale Programmierung mit Haskell 1123

Anfang und Ende des Funktionsrumpfes Wiederholung: C code(λv 1 v 2 v n e, β, sl) = L 1 : targ n V code(e, [v i (LOC, i), v j (GLOB, j)], 0) return n L 2 : targ n testet die Anzahl der vorhandenen Argumente Genug Argumente: Mit dem erzeugten V code weitermachen Zuwenig Argumente: Neues F UNV AL-Objekt erzeugen return n: Wenn ursprünglich mehr Argumente vorhanden waren, als zur Anwendung der Funktion erforderlich sind, muss das Ergebnis der Funktionsanwendung wieder ein Funktionsobjekt sein, das unmittelbar anschließend ausgeführt wird Funktionale Programmierung mit Haskell 1124

Argumenttest Stapelstruktur bei Konstruktion eines FUNVAL-Objektes: vor targ nach targ Halde P C old SP f f F UN : P C F P old v F P GP old GP a m v V ECT OR : a m SP a 1 a 1 Expansion von targ n: if SP F P < n then h := ST [F P 2] ST [F P 2] := new(f UN : P C 1, new(v ECT OR : ST [F P + 1],, ST [SP ]), GP ); GP := ST [F P ] SP := F P 2 F P := ST [F P 1] P C := h Funktionale Programmierung mit Haskell 1125

Rücksprung Wenn ursprünglich zuviele Argumente vorhanden waren, muss das Ergebnis wieder ein Funktionsobjekt sein: if SP = F P + 1 + n then / Delete stack frame and return / else if HP [ST [SP ]]tag F UNV AL then error / Repeat function application / Stapelstruktur: vor return nach Fall 1 nach Fall 2 P C old SP result P C old F P old F P old F P GP old F P GP old a m a m = a m a 1 a n+1 = a q+1 SP result a q SP a 1 Funktionale Programmierung mit Haskell 1126