Funktionale Programmierung am Beispiel Haskell



Ähnliche Dokumente
Programmierparadigmen: Funktionale Programmierung

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

L10N-Manager 3. Netzwerktreffen der Hochschulübersetzer/i nnen Mannheim 10. Mai 2016

1 Vom Problem zum Programm

Arbeiten mit UMLed und Delphi

Anleitung über den Umgang mit Schildern

Objektorientierte Programmierung für Anfänger am Beispiel PHP

1 Mathematische Grundlagen

1 topologisches Sortieren

Persönliche Zukunftsplanung mit Menschen, denen nicht zugetraut wird, dass sie für sich selbst sprechen können Von Susanne Göbel und Josef Ströbl

Programmieren in Haskell Einführung

4. BEZIEHUNGEN ZWISCHEN TABELLEN

Informationsblatt Induktionsbeweis

AutoCAD Dienstprogramm zur Lizenzübertragung

Funktionale Programmierung mit Haskell

ONLINE-AKADEMIE. "Diplomierter NLP Anwender für Schule und Unterricht" Ziele

Mind Mapping am PC. für Präsentationen, Vorträge, Selbstmanagement. von Isolde Kommer, Helmut Reinke. 1. Auflage. Hanser München 1999

Handbuch ECDL 2003 Basic Modul 5: Datenbank Access starten und neue Datenbank anlegen

Programmierkurs Java

Erstellen einer Collage. Zuerst ein leeres Dokument erzeugen, auf dem alle anderen Bilder zusammengefügt werden sollen (über [Datei] > [Neu])

Mehr Geld verdienen! Lesen Sie... Peter von Karst. Ihre Leseprobe. der schlüssel zum leben. So gehen Sie konkret vor!

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3

Grundbegriffe der Informatik

Punkt 1 bis 11: -Anmeldung bei Schlecker und 1-8 -Herunterladen der Software

Lernerfolge sichern - Ein wichtiger Beitrag zu mehr Motivation

1. Standortbestimmung

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

Primzahlen und RSA-Verschlüsselung

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

Gutes Leben was ist das?

Flyer, Sharepics usw. mit LibreOffice oder OpenOffice erstellen

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

Serienbrieferstellung in Word mit Kunden-Datenimport aus Excel

Woche 1: Was ist NLP? Die Geschichte des NLP.

CodeSaver. Vorwort. Seite 1 von 6

Gruppenrichtlinien und Softwareverteilung

Mediator 9 - Lernprogramm

Software Engineering Klassendiagramme Assoziationen

Handbuch. NAFI Online-Spezial. Kunden- / Datenverwaltung. 1. Auflage. (Stand: )

Ist Fernsehen schädlich für die eigene Meinung oder fördert es unabhängig zu denken?

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

Rohstoffanalyse - COT Daten - Gold, Fleischmärkte, Orangensaft, Crude Oil, US Zinsen, S&P500 - KW 07/2009

Workshop: Wie ich mein Handikap verbessere erfolgreich Leben mit Multiple Sklerose!

Hohe Kontraste zwischen Himmel und Landschaft abmildern

Anleitung für die Version von online 1. Schritt: Rufen Sie die Website auf...

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

Warum Sie jetzt kein Onlinemarketing brauchen! Ab wann ist Onlinemarketing. So finden Sie heraus, wann Ihre Website bereit ist optimiert zu werden

Kreativ visualisieren

Erweiterung der Aufgabe. Die Notenberechnung soll nicht nur für einen Schüler, sondern für bis zu 35 Schüler gehen:

Dokumentation IBIS Monitor

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

Wie halte ich Ordnung auf meiner Festplatte?

Alle Schlüssel-Karten (blaue Rückseite) werden den Schlüssel-Farben nach sortiert und in vier getrennte Stapel mit der Bildseite nach oben gelegt.

Zwischenablage (Bilder, Texte,...)

Information zum Projekt. Mitwirkung von Menschen mit Demenz in ihrem Stadtteil oder Quartier

Zahlenwinkel: Forscherkarte 1. alleine. Zahlenwinkel: Forschertipp 1

Windows. Workshop Internet-Explorer: Arbeiten mit Favoriten, Teil 1

MORE Profile. Pass- und Lizenzverwaltungssystem. Stand: MORE Projects GmbH

Grundlagen der Theoretischen Informatik, SoSe 2008

Herzlich Willkommen beim Webinar: Was verkaufen wir eigentlich?

Informationen zur Verwendung von Visual Studio und cmake

Nicht kopieren. Der neue Report von: Stefan Ploberger. 1. Ausgabe 2003

Liebe oder doch Hass (13)

1. Was ihr in dieser Anleitung

Doku zur Gebäudebrüter Datenbank

Welche Gedanken wir uns für die Erstellung einer Präsentation machen, sollen Ihnen die folgende Folien zeigen.

Erstellen von x-y-diagrammen in OpenOffice.calc

Die Captimizer BTZ-Datei 2015

Statuten in leichter Sprache

10 Erweiterung und Portierung

Downloadfehler in DEHSt-VPSMail. Workaround zum Umgang mit einem Downloadfehler

GEONET Anleitung für Web-Autoren

Abschluss Version 1.0

Professionelle Seminare im Bereich MS-Office

Kulturelle Evolution 12

Geld Verdienen im Internet leicht gemacht

Das Leitbild vom Verein WIR

iphone- und ipad-praxis: Kalender optimal synchronisieren

BUCHHALTUNG BUCHFÜHRUNG WO IST ER EIGENTLICH? - DER UNTERSCHIED?

TESTEN SIE IHR KÖNNEN UND GEWINNEN SIE!

Repetitionsaufgaben Wurzelgleichungen

Projektmanagement in der Spieleentwicklung

Pädagogik. Melanie Schewtschenko. Eingewöhnung und Übergang in die Kinderkrippe. Warum ist die Beteiligung der Eltern so wichtig?

Wir arbeiten mit Zufallszahlen

icloud nicht neu, aber doch irgendwie anders

OECD Programme for International Student Assessment PISA Lösungen der Beispielaufgaben aus dem Mathematiktest. Deutschland

Krippenspiel für das Jahr 2058

Einrichten einer mehrsprachigen Webseite mit Joomla (3.3.6)

Viele Bilder auf der FA-Homepage

Datenbanken Kapitel 2

Artikel Schnittstelle über CSV

Versetzungsgefahr als ultimative Chance. ein vortrag für versetzungsgefährdete

Daten sammeln, darstellen, auswerten

Spielmaterial. Hallo! Ich bin der kleine AMIGO und zeige euch, wie dieses Spiel funktioniert. Viel Spaß! von Liesbeth Bos

Stellen Sie bitte den Cursor in die Spalte B2 und rufen die Funktion Sverweis auf. Es öffnet sich folgendes Dialogfenster

Präventionsforum+ Erfahrungsaustausch. HANDOUT GRUPPEN-ADMINISTRATOREN Anlage zum Endnutzer-Handbuch. Stand: Änderungen vorbehalten

Papa - was ist American Dream?

Einführung in die Programmierung

Mit dem Tool Stundenverwaltung von Hanno Kniebel erhalten Sie die Möglichkeit zur effizienten Verwaltung von Montagezeiten Ihrer Mitarbeiter.

Transkript:

Funktionale Programmierung am Beispiel Haskell Heiko Waldschmidt Matrikel Nr. 02241074 Baunatal, den 13.06.2004

Inhaltsverzeichnis 1. Einleitung 3 2. Die Geschichte der funktionalen Programmierung 3 2.1 Das Lambda-Kalkül 4 3. Prototypen Experiment 5 4. Syntaktische Möglichkeiten von Haskell 6 4.1 Typisierung 6 4.2 Syntaktische Besonderheiten 7 4.3 Lazy evaluation 7 4.4 Modularisierung 9 4.5 Seiteneffekte 11 4.6 Pattern Matching und Case 11 4.6.1 As-Pattern 12 4.6.2 Wild Cards 12 4.6.3 With-Pattern / guards 12 4.6.4 Case 13 4.6.5 Let Expressions 13 4.6.6 Where clauses 14 4.7 IO 14 4.8 Typ classes Typklassen 15 4.9 Weitere Möglichkeiten von Haskell 16 5. Interpreter und Compiler 17 6. Fazit 17 7. Literaturverzeichnis 19 Seite 2

1. Einleitung Dieser Vortrag ist im Rahmen des Seminars Programmiersprachen bei Frau Prof. Leopold entstanden. Er soll Aufzeigen wo die Vorteile (und Nachteile) von funktionaler Programmierung und speziell von Haskell liegen und bei welchen Problemen diese Sprache bzw. funktionale Programmierung bevorzugt eingesetzt werden sollte. Um dies zu zeigen beginne ich zunächst mit der geschichtlichen Entwicklung von funktionaler Programmierung bis zur Entwicklung von Haskell 98. Als zweites versuche ich ein (meiner Meinung nach beeindruckendes) Beispiel vorzustellen an dem man erkennen kann, das funktionale Programmierung zu verwenden deutliche Vorteile haben kann. Anschließend versuche ich einige Möglichkeiten und Vorteile dieser Sprache aufzuzeigen und diese am Schluss noch einmal kurz aufzugreifen. 2. Die Geschichte der funktionalen Programmierung Die funktionale Programmierung entstand als noch kaum jemand an die heutige Art der Programmierung (mittels Höherer Programmiersprachen) dachte. Ihr Ursprung liegt in der Mathematik. Church entwickelte 1932 das Lambda-Kalkül, dessen Nutzen in der Programmierung 1936 von Kleene und Rosser bewiesen wurde d.h. das nachgewiesen wurde das man das Lambda-Kalkül zur Umsetzung von Funktionen in der Informatik nutzen kann. 1937 bewies Turing, das das Lambda-Kalkül turing-äquivalent ist. Heutige rein funktional geschriebene Programme können in Lambda-Kalküle umgewandelt werden. 1960 wurde LISP als erste funktionale Sprache von McCarthy entwickelt. Ein großer Vorteil von LISP liegt in seiner Erweiterbarkeit und somit wurden einige erweiterte Sprachen entwickelt (z.b. Common LISP and Scheme). Ende der 70er entwickelte Backus FP. Er hatte die Idee von Funktionen höherer Ordnung und setzte diese in FP um. Gleichzeitig entwickelte man in Edinburgh an der Universität ML. Man suchte nach einer Sprache, mit der man Theoreme beweisen konnte. Auch aus ML entstanden einige Dialekte (z.b. SML, CAML). Seite 3

Eine weitere Sprache auf dem Weg bis zur Entwicklung von Haskell ist Miranda. Miranda wurde 1985 1986 entwickelt. In Miranda wurde zum ersten Mal lazy evaluation benutzt. Die Entwickler von Miranda wurden gefragt ob man es als Basis zur Entwicklung von Haskell nutzen dürfte, doch sie lehnten ab. Die heute in der Industrie meist genutzte funktionale Sprache ist Erlang, das ende der 80er von Ericsson für Anwendungen in der Telekommunikation entwickelt wurde. Mit Erlang ist parallele funktionale Programmierung möglich. Haskell entstand 1990 (Version 1.0). In Haskell wurden die Ideen der älteren funktionalen Programmiersprachen vereinigt (Funktionen höherer Ordnung, type inference, und lazy Semantik. Eine Neuheit von Haskell sind Typklassen mit denen man Methoden auf ähnlich Art und Weise wie in der Objekt orientierten Programmierung Überladen kann.) Bis 1997 entstanden vier weitere Versionen (bis 1.4). Auf dem Haskell Workshop 1997 in Amsterdam wurde beschlossen, dass eine stabile einheitliche Variante nötig sei. Hierdurch entstand Haskell 98. [Hask] 2.1 Das Lambda-Kalkül Das Lambda-Kalkül ist eine mathematische Schreibweise für Funktionen. Dazu ein Beispiel: mittelwert == λ a, b. ((a+b)/2) -- nun das Beispiel in Haskell: mittelwert (a,b) == ((a+b)/2) Der Vorteil des Lambda-Kalküls liegt darin, dass Programme die im Lambda Kalkül geschrieben sind bezüglich Korrektheit bewiesen werden können. Alle Programme die rein funktional geschrieben wurden können in Lambda-Kalküle umgewandelt werden. Somit kann man die Korrektheit dieser Programme - und damit auch aller Programme die in Haskell 98 geschrieben wurden - beweisen. Hierzu gibt es auch Seite 4

eine Berechnungsvorschrift (evtl. ist es sogar ein Algorithmus). Für weitere informationen siehe [Pepp]. 3. Prototypen Experiment 1989 wurde von der ARPA (Advanced Research Project Agency) und dem Office of Naval Research (ONR) ein Projekt ins leben gerufen, bei dem es darum ging Sprachen und Tools zur Verbesserung der Erstellung von Prototypen zu entwickeln. 1993 würde im Zuge diese ProtoTyp Programmes ein Versuch durchgeführt. Es ging darum einen Prototyp in mehrere Programmiersprachen zum selben Problem zu schreiben. Programmanforderungen: Ein Geo-Server bekommt als Eingabe Informationen über Standorte von Schiffen, Flugzeugen etc. und anderen Sicherheitsrelevanten Objekten. Als Ausgabe soll er die Beziehungen zwischen diesen Objekten liefern. Freundliche Schiffe, Kriegsschiffe, Flugzeuge sollen durch Dreiecke dargestellt werden. Hinzu kommen Zonen, die dargestellt werden sollten z.b. Waffenreichweite, Flugzonen, Regionen von befreundeten Schiffen,die beschützt werden müssen. (Die Beschreibung war noch deutlich detaillierter, doch würde hier den Rahmen sprengen.) Die Beurteilung der fertigen Prototypen übernahm ein Komitee der Navy. Die Ergebnisse: Language Lines of Code Lines of Documentation Development time (hours) (1) Haskell 85 465 10 (2) Ada 767 714 23 (3) Ada9X 800 200 28 (4) C++ 1105 130 - (5) Awk\Nawk 250 150 - (6) Rapide 157 0 54 (7) Griffin 251 0 34 (8) Proteus 293 79 26 (9) Relational Lisp 274 12 3 ((10) Haskell) 156 112 8 Seite 5

(1) wurde von Mark P. Jones geschrieben einem der Autoren von [EiSPP]. Die Auswertung der Programm und der oben aufgeführten Tabelle ergab, dass das Programm in Haskell wesentlich kürzer war als die meisten anderen. (Ich bin mir nicht sicher wessen Meinung dies ist. Es handelt sich entweder um die des Navy Komitees oder die der Autoren von [EiSPP].) Es hatte auch eine im Vergleich sehr kurze Entwicklungszeit und war trotz allem eines der am besten kommentierten Programme. Der Code wurde als sehr gut lesbar bzw. sehr einfach zu verstehen beurteilt. Hierdurch zeigt sich das Haskell sich besonders gut für Prototypenentwicklung eignet. Für weitere Informationen siehe [EiSPP] 4. Syntaktische Möglichkeiten von Haskell 4.1 Typisierung Haskell ist stark typisiert. Die Typisierung kann allerdings implizit durch Haskell erfolgen, d.h. es ist keine explizite Typangabe notwendig. Dies wird im englischen als type inference bezeichnet. Handelt es sich bei dem letzten Schritt vor der Übergabe der Rüchgabeparameter z.b. um eine Division von zwei Integer, do setzt Haskell den Typ des Rückgabeparameters auf Integer und verfolgt die Auswirkungen dieser Typfestlegung über das ganze Programm um evtl. weitere Typen\Parameter festlegen zu können. Diese Typisierung hat den Vorteil, dass schon zu compile-zeit Fehler entdeckt werden können. [agith] Seite 6

4.2 Syntaktische Besonderheiten In Haskell gibt es ein paar Besonderheiten. Um Fehler zu vermeiden, wurde auf die Semikolons am Ende der Zeilen verzichtet, da diese in anderen Programmiersprachen von den Programmierern häufig vergessen werden. Ungewöhnlich in Haskell ist, dass die Einrückung der Zeilen vom Compiler mit ausgewertet wird. Rückt man die Zeilen falsch ein kann dies zu falscher Semantik führen. Darauf muss man speziell bei if Verschachtelungen achten. Weitere Informationen findet man in meinen Quellen. [PePP] 4.3 Lazy evaluation Lazy evaluation (Bedarfauswertung) bedeutet, dass Ausdrücke immer erst dann ausgewertet werden, wenn sie benötigt werden und dass eine Auswertung immer nur einmal vorgenommen wird. Beispiel.: f(g(x)) dabei sei f eine Funktion, die auf einer Liste arbeitet. Diese Liste wird ihr von der Funktion g übergeben und zwar ein Element nach dem anderen. Die Funktion g erzeugt (rekursiv) eine unendlich lange Liste. Würde es sich hierbei nicht um lazy evaluation handeln, würde das bedeuten, dass die Funktion g unendlich lange läuft und wir hätten wahrscheinlich ein schlechtes Programm geschrieben. Durch lazy evaluation geschieht nun aber folgendes: Die äußere Funktion f wird zuerst gestartet (wie auch ohne lazy evaluation) und fordert einen Wert / ein Listenelement von der Funktion g an. Anschließend wird dieser Wert der Funktion f bearbeitet und dann fordert sie wieder einen Wert an. Hier entsteht nun der Unterschied, erst jetzt erzeugt die Funktion g ein weiteres Listenelement. Wenn die Funktion f sich beendet, dann wird auch die Funktion g beendet. Dieses Seite 7

Programm läuft also nur endlos, wenn f auch eine Endlosschleife erzeugt und von keiner höher geordneten Funktion beendet wird. Lazy evaluation kann also genutzt werden, damit man sich in niedrig geordneten Funktionen keine Gedanken darüber machen braucht wie lange eine zu erzeugende Liste sein muss, da die höher geordnete Funktion sich darum kümmern kann. Hierdurch kann man die Funktion auch für mehrere höher geordnete Funktionen nutzen, die eine unterschiedliche Anzahl an Werten benötigen. Durch lazy evaluation kann man also unendliche Listen erzeugen. Man hat hierdurch eine gute Möglichkeit sehr einfach unendliche Datenstrukturen zu erzeugen (dies geht aber auch noch anders). Ein Nachteil besteht allerdings auch wieder darin, dass sich höher geordnete Funktionen um das Enden der Funktion kümmern müssen, wenn das Programm nicht endlos laufen soll. Dies kann zu Fehlern führen, wenn der Programmiere vergisst sich darum zu kümmern. Eine Möglichkeit dies zu verhindern besteht in entsprechender Modularisierung (siehe Modularisierung), durch welche man nur bestimmten Funktionen erlaubt auf eine bestimmte endlos laufende Funktion zurückzugreifen. Dass eine Auswertung nur einmal in einem Programm durchgeführt wird, bedeutet dass z.b. 3+4 nur einmal berechnet wird, selbst wenn diese Rechnung an den unterschiedlichsten Stellen im Programm geschieht. Hierdurch kann Rechenleistung gespart werden, allerdings erhöht die natürlich auch den Speicherverbrauch, da alle Auswertungen zunächst im Speicher verbleiben. Die führt dazu dass man garbage collection benötigt. [agith] [PePP] Seite 8

4.4 Modularisierung Hier zunächst ein Beispiel an dem ich die Modularisierung erklären will: module A where import B funktiona = (...) ( ) module B where import C funktionb = (...) ( ) module C where funktionc = (...) funktionc2 = (...) ( ) In Haskell wird hier folgendes passieren: Modul B importiert die Funktionen aus Modul C und Modul A importiert die Funktionen aus Modul B; Modul A importiert allerdings nicht die Funktionen aus C, da Module in Haskell die Funktionen die sie importieren nicht wieder automatisch exportieren. Um in Modul A die Funktionen aus C zu importieren, müsste man entweder import C hinzufügen oder Modul B folgendermaßen abändern: module B (funktionb, module C) where (...) oder Seite 9

module B (funktionb, funktionc, ) where ( ) je nachdem ob man alle Funktionen oder nur bestimmte Funktionen exportieren will. Hierbei handelt es sich um einen gezielten Export. In Haskell gibt es nicht nur gezielten Export sondern auch gezielten Import. z.b.: module B where import C (funktionc) Hier wird aus Modul C nur noch die funktionc importiert. Alternativ kann man auch eine Negativliste angeben, also alle Funktionen die nicht importiert werden sollen. module B where import C hiding (funktionc2) Zusätzlich sind noch Umbenennungen der zu importierenden Funktionen möglich: module B where import C (funktionc) renaming (funktionc to helloworld) Um kurz auf das Problem der Endlosrekursionen aus dem Kapitel lazy evaluation zurückzukommen: Man kann die Modularisierung dazu nutzen, die lazy functions vom Export auszuschließen, so dass sie niemand benutzt, der evtl. dann nicht weiß was er da tut. Haskell erlaubt es also gezielt zu importieren und zu exportieren. Man kann deutlich genauere Einschränkungen treffen als z.b. in Java. [agith] Seite 10

4.5 Seiteneffekte In rein funktionaler Programmierung sind keine Seiteneffekte erlaubt, da funktionale Programmierer davon überzeugt sind das durch Seiteneffekte viele Fehler entstehen. Eine Funktion soll immer nur genau eine Sache tun: ein gewünschtes Ergebnis zurückliefern und dabei keine anderen Dinge tun wie z.b. Variablen Hochzuzählen. Ein Extrembeispiel ist folgendes: a[i++] = b[i++] + c[i++]; Einem Programmierer ist meist nicht klar was hier passiert. Dies hängt häufig vom verwendeten Compiler ab. Damit so etwas erst gar nicht passieren kann sind Seiteneffekte in Haskell nicht erlaubt. Dies wird hauptsächlich dadurch verhindert, dass es in rein funktionaler Programmierung keine Variablen gibt. Man kann nur Konstanten deklarieren die dann zur Substitution genutzt werden können (siehe Let und where clauses). Was auch noch notwendig und möglich ist sind Parameter, an denen für gewöhnlich aber nicht mehr manipuliert wird (hier entstehen also keine Seiteneffekte). Es kann sich bei den Parametern auch um Tupel handeln (siehe Quellen aus dem Literaturverzeichnis). [Zuen] [FPML] 4.6 Pattern Matching und Case Haskell bietet viele Möglichkeiten des Pattern Matching die ich hier an Beispielen erklären will. In Haskell gibt es außerdem ein Case, wofür ich auch ein kurzes Beispiel aufführe. Seite 11

4.6.1 As-Pattern Die Funktion: f (x:xs) = x:x:xs verdoppelt das erste Element einer Liste, dies kann in Haskell auch auch mit einem as-pattern geschrieben werden. Das entsprechende as-pattern zu obigem Beispiel sieht folgendermaßen aus: f s@ (x:xs) = x:s [agith] 4.6.2 Wild Cards: Funtionen, die head bzw. tail zurückgeben: head (x:_) tail (_:xs) = x = xs Der _ ist hier eine wild card. Da in der funktion head, tail nicht mehr weiter gebraucht wird, benutzt man hier die wild card. [agith] 4.6.3 With-Pattern / guards sign x x > 0 = 1 x == 0 = 0 x < 0 = -1 Seite 12

Diese pattern werden guards genannt und mit dem dargestellt. Ein guard ist immer ein boolscher Ausdruck, ist er wahr, so wird die Funktion zu dem bewachten Ausdruck hin ausgewertet. Die guards werden von oben nach unten überprüft. Pattern matching zur Definition von Funktionen+ take 0 _ = [] take _ [] = [] take n (x:xs) = x : take (n-1) xs [agith] [PePP] 4.6.4 Case So schreibt man die take Funktion mit einem Case: Take m ys = case (m,ys) of (0,_) -> [] (_,[]) -> [] (n,x:xs) -> x : take (n-1) xs [agith] 4.6.5 Let Expressions let a = b + c in a/d d = e * f Let-Ausdrücke dienen zur Vereinfachung von Ausdrücken. Hier geschieht nichts anderes als eine Substitution. Im in Teil darf nur ein Ausdruck vorkommen. Sollte Seite 13

man mehrere benötigen, so muss man auf where clauses zurückgreifen. Es handelt sich hierbei um lokale Definitionen. [agith] 4.6.6 Where clauses funktiona a = (b,c) where b = - (abs a) c = abs a [agith] 4.7 IO IO stellt in funktionaler Programmierung ein großes Problem dar. Die meisten funktionalen Programmiersprachen erlauben hier Seiteneffekte um das Problem zu lösen obwohl sie diese eigentlich strikt ablehnen. Dieses Problem gibt es weil IO etwas Imperatives darstellt. Ließ ein Zeichen mache etwas damit und gib es wieder aus, ist eine typische imperative Anweisung die sich in funktionaler Programmierung nur schlecht lösen lässt In Haskell geschieht IO rein funktional. In Haskell gibt es dafür einen eigenen Typ mit Namen IO. Die Funktion main muss in Haskellprogrammen vorhanden sein und muss einen IO Typ haben. Für gewöhnlich IO (). Der Code für ein einfaches getchar, es ließt ein Zeichen und gibt es gleich wieder aus: main :: IO () main = do c <-getchar putchar c Seite 14

Nach einem do folgen statements, in diesem Fall besteht das Statement aus einem Pattern (c) das durch <- an die Funktion getchar gebunden wird. Die Statements werden der Reihe nach ausgeführt. Das zweite Statement ist putchar c, das in diesem Fall eine Funktion ist. (Die dritte Möglichkeit für Statements sind lokale Definitionen durch let.) Dies ist der Code zum Einlesen von Zeilen in Haskell: getline :: IO String getline = do c <- getchar if c == \n then return else do l <- getline return (c:l) Die Funktion getline ließt Elemente von Typ IO und gibt einen String zurück. Durch do wird das Pattern c an die Funktion getchar gebunden. Solange kein Zeilenende eingelesen wird, wird das Zeichen auf den Stack gelegt und gleichzeitig wird getline an l gebunden. Die funktion getline ruft sich anschließend wieder rekursiv auf. Der rekursive Aufruf erfolgt so lange bis die Zeile zu Ende ist, dann wird der Stack wieder abgebaut und zwar in umgekehrter Reihenfolge zum Aufbauen des Stacks, d.h. die Zeile wird von hinten nach vorne wieder zusammengesetzt. Dies geschieht durch return (c:l). [agith] 4.8 Type Classes Typklassen Eine Besonderheit von Haskell sind Typklassen. Aus Java kennt man Überladung von Klassen bzw. Funktionen aus Klassen. Haskell versucht diese Idee auch für sich zu nutzen in dem es ähnliche Möglichkeiten für Typen bietet. Da zu gibt es in Haskell eine Klassehierarchien der Standarttypen. (Diese ist zu finden in [HaKu] ) Seite 15

Hier nun ein Beispiel: class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool Hierdurch definiert man eine Klasse von Typen. Sie beinhaltet alle Typen für die die Funktionen == und /= definiert sind. Man kann nun eine Funktion schreiben, die einen oder mehrere Parameter dieser Typklasse benutzt. Diese Funktion definiert man somit für alle Parameter für die die Funktionen == und /= definiert sind. Dadurch dass in Haskell auch gewöhnliches Überladen erlaubt ist kann man somit höher geordnete Funktionen schon dadurch Überladen, das man Funktionen als Parameter benutzt, die ihrerseits einen Typ einer Typklasse zurückgeben. Man Überlädt Funktionen dadurch in Bezug auf ihre Verschachtelung von Innen nach außen und erbt damit in einer höheren Funktion die Überladung. 4.9 Weitere Möglichkeiten von Haskell Wietere Möglichkeiten die Haskell bietet sind Monaden, garbage collection (siehe [Ggch]), lazy patterns, Polymorphie, Überladen, Funktionen höherer Ordnung, Tupel, Currying, unendliche Datenstrukturen. Diese Möglichkeiten kann ich ihm Rahmen dieses Vortrages nicht aufführen, da dies denselben sprengen würde. Einige dieser Dinge wurden auch schon im Vortrag meines Kommilitonen Oliver Trosien [OlTr] näher erläutert und somit möchte ich auf seinen Vortrag und auf meine anderen Quellen Verwiesen. Seite 16

5. Interpreter und Compiler Es gibt mehrere Interpreter und Compiler für Haskell. Der Standard-Interpreter ist Hugs. Er läuft auf fast allen Betriebssystemen (Unix, Linux, Windows 3.x, Win 32 and Macintoshs) und kann als interaktiver Interpreter genutzt werden. Es gibt mehrere Compiler (GHC, nhc98, (HBI) und HBC, Helium) die unterschiedliche Vorteile haben. Sie sind alle (auch Hugs) frei verfügbar und laufen auf unterschiedlich vielen Betriebssystemen. GHC erzeugt den schnellsten Code. Helium implementiert Haskell nur unvollständig hat allerdings eine besonders verständliche Fehlerausgabe und ist daher speziell zum lernen von Grundzügen von Haskell gut geeignet. GHC, nhc98, HBI und HBC implementieren mehr als den Haskell 98 Standard und man sollte sich dessen bewusst sein, da ein Haskell Programm evtl. mit einem anderen Compiler nicht mehr funktioniert. Mit HBI und HBC wird versucht dem Programmierer die Vorteile von Compilern und Interpretern zu ermöglichen. Denn sie implementieren den gleichen Code auf die gleiche Art wobei HBI ein Interpreter und HBC ein Compiler ist. Die Vorteile eines Compilers liegen darin, das das fertige Programm schneller ausgeführt werden kann und die eines Interpreters liegen darin, das man es als Programmierer leichter hat, da man das Programm nicht immer erst kompilieren muss um es zu testen sondern alles in einem Schritt erledigen kann. [Hask] 6. Fazit Wie ich hoffentlich zumindest in einigen Bereichen zeigen konnte hat funktionale Programmierung einige Vorteile. Die Korrektheit von Haskellprogrammen kann mit Hilfe des Lambda-Kalkül bewiesen werden. Haskell vermeidet Fehler durch Vermeidung von Seiteneffekten und starke Typisierung. Zusätzlich wird zur Fehlervermeidung noch auf Semikolons zum Abschluss von Zeilen verzichtet was in anderen Sprachen zu Fehlern führt. Typen können von Haskell selbstständig erkannt werden und müssen nicht explizit angegeben werden. Haskell bietet unendliche Datenstrukturen und spart Rechenzeit durch lazy evaluation und auch garbage collection um Daten die zunächst für lazy evaluation zunächst aufgehoben werden auch wieder aus dem Speicher zu entfernen. Die Fehler die durch Endlosrekursionen Seite 17

mit Hilfe von lazy evaluation entstehen können, können durch eine sehr viel genauere Modularisierung vermieden werden. Diese Art der Modularisierung kann natürlich auch noch zu anderen / den üblichen Zwecken eingesetzt werden. Hinzu kommt pattern matching und etwas auf was Haskell Programmierer viel wert legen, nämlich das es geschafft wurde auch IO rein funktional zu behandeln. Und Typklassen bieten erweiterte Möglichkeiten der Überladung und sind Neuentwicklung für Haskell. Haskell besitzt auch umfangreiche Bibliotheken (in denen auch die obige Funktion getline schon implementiert ist) und stellt sowohl Interpreter als auch Compiler zur frei zur Verfügung. Hinzu kommen noch einige Möglichkeiten auf die ich nicht näher eingegangen bin (siehe 4.10). An meinem Beispiel des Prototypen Experiments lässt sich auch erkennen, dass man sich Haskell auf jeden Fall ansehen sollte wenn man vorhat einen Prototypen zu schreiben. Haskell scheint sich außerdem für die Programmierung von Compilern & Interpretern (es gibt einen LaTeX Preprocessor, ein Haskell Compiler Front End, einen Interpreter für das Lambda-Kalkül), Netzwerk- und Webanwendungen (es gibt einen Webserver HWS-WP, linkchk ein Monitor für Netzwerkverbindungen in einem LAN) und Grafikprogramme (QuakeHaskell und einen Grafikeditor) zu eignen. Weiter Programme siehe [HaskP]. Ich kann also abschließend sagen, das Haskell mehr Möglichkeiten bietet, als ein Referat in diesem Umfang erschlagen kann und Haskell damit eine durchaus Interessante und nützliche Sprache darstellt. Seite 18

7. Literaturverzeichnis [Pepp] Prof. Dr. Peter Pepper, Funktionale Programmierung in OPAL, ML, HASKELL und GOFER, Springer, Berlin Heidelberg New York, 2. Auflage, 2003 [CoFP] Simon Thompson, The Craft of Funktional Programming, Addison Wesley Longman Limited, Dorchester, 1999 [FpuH] Antony J.T.Davie, An introduktion to funktional programming using Haskell, Cambridge University Press, 1992 [Hask] www.haskell.org, die Haskell Webseite [HaskP] http://www.haskell.org/practice.html [WhyFp] John Hughes, Why Functional Programming Matters http://www.md.chalmers.se/~rjmh/papers/whyfp.pdf [agith] Paul Hudak, John Peterson, Joseph Fasel, A Gentle Introduction to Haskell Version 98, Yale Univesity & Los Alamos National Laboratory, June 2000 http://www.haskell.org/tutorial/ [EiSPP] Paul Hudak, Mark P. Jones, Haskell vs. Ada vs. C++ vs Awk vs.... An Experiment in Software Prototyping Productivity, Yale Univesity Department of Computer Science, 4 July 1994 [Ggch] Patrick m Sansom, Simon L. Peyton Jones,Generational garbage collection for Haskell, Dept. of Compunter Science, University of Glasgow [HaKu] Haskell-Kurs www.informatik.uni-bonn.de/~ralf/teaching/hskurs_toc.html [OlTr] Oliver Trosien, Funktionale Programmierung am Beispiel ML, http://www.se.etechnik.uni-kassel.de/se/fileadmin/pm/courses/prog-seminar/funk-ml.pdf Seite 19

[Zuen] Aus einer Vorlesung von Professor Zündorf, Uni-Kassel, 2004 [FPML] Oliver Trosien, Funktionale Programmierung am Beispiel ML, 2004 Seite 20