Posted on Leave a comment

Haskell: Beispiel für eine funktionale Programmiersprache

Haskell: Beispiel für eine funktionale Programmiersprache

In unserem letzten Artikel haben wir die funktionale Programmierung angesprochen. Dabei handelt es sich um ein Programmierparadigma, das sich stark von den gängigen Formen der Programmgestaltung unterscheidet. Während wir dabei vorwiegend auf die theoretischen Aspekte der funktionalen Programmierung eingegangen sind, soll nun ein praktisches Beispiel folgen. Hierfür verwenden wir die Programmiersprache Haskell. Hierbei handelt es sich um eine rein funktionale Programmiersprache, sodass die Besonderheiten dieser Vorgehensweise besonders gut zur Geltung kommen. Zwar ist die Verbreitung von Haskell im Vergleich zu imperativen Sprachen wie Python, Java oder C nur ausgesprochen gering. Im Bereich der rein funktionalen Programmiersprachen handelt es sich hierbei jedoch um die am häufigsten verwendete Sprache.

Ein Überblick über die Geschichte

Die erste funktionale Programmiersprache entstand bereits in den 1950er Jahren. Hierbei handelt es sich um LISP. In den folgenden Jahren kamen viele weitere hinzu, sodass es in den 80er Jahren mehr als ein Dutzend verschiedene funktionale Sprachen gab. Das führte dazu, dass die Forschung in diesem Bereich nicht einheitlich war. Das erschwerte die Zusammenarbeit. Es kam hinzu, dass viele dieser Sprachen bereits stark veraltet waren.

1985 erschien die Programmiersprache Miranda. Diese erfüllte die Anforderungen an eine moderne Programmiersprache deutlich besser. Außerdem setzte sie die Lazy Evaluation um, die die Effizienz der Programme deutlich erhöhte. Das führte dazu, dass immer mehr Wissenschaftler, die in diesem Bereich tätig waren, Miranda verwendeten. Allerdings brachte diese Sprache ein großes Problem mit sich: Hierbei handelte es sich um proprietäre Software. Daher entstand in der Wissenschaft der Wunsch, eine neue funktionale Programmiersprache zu entwickeln, die den Anforderungen der modernen Informatik entspricht und Lazy Evaluation umsetzt. Außerdem sollte es sich dabei um freie Software handeln. Im Hintergrund stand dabei auch der Gedanke, eine einheitliche Sprache für die Forschung an funktionalen Programmen zu erschaffen.

Nachdem die Miranda-Entwickler eine Anfrage zur Kooperation negativ beantwortet hatten, entstand ein eigenes Entwickler-Team unter der Leitung von Simon Peyton Jones, Paul Hudak und Philip Wadler. Diese entwickelten eine neue funktionale Programmiersprache. Dieser gaben sie den Namen Haskell – zu Ehren des US-amerikanischen Mathematikers Haskell Brooks Curry. Dieser entwickelte im Rahmen seiner Doktorarbeit – die er übrigens an der Universität Göttingen einreichte – die kombinatorische Logik. Diese stellte eine wichtige Grundlage bei der Entwicklung der funktionalen Programmierung dar. Die erste Version von Haskell erschien 1990.

C++ Programmieren für Einsteiger 14.99 € Verfügbar In den Warenkorb

Die Besonderheiten von Haskell

Die wichtigste Eigenschaft von Haskell besteht darin, dass es sich hierbei um eine rein funktionale Programmiersprache handelt. Das bedeutet, dass Funktionen ausschließlich Werte zurückgeben. Sie verändern die Zustände der Programmvariablen jedoch nicht. Deshalb haben sie keinerlei Seiteneffekte. Das hilft nicht nur dabei, unerwünschte Effekte zu vermeiden. Darüber hinaus ist es auf diese Weise deutlich einfacher, die Richtigkeit einer Funktion zu beweisen.

Da Variablen ihren Zustand nicht verändern, haben sie während des kompletten Programmablaufs den gleichen Wert. Sie sind daher wie Konstanten in einem imperativen Programm zu verstehen. Variablen, denen Sie unterschiedliche Werte zuweisen können, existieren in Haskell nicht.

Haskell wendet außerdem die Lazy Evaluation an – auf Deutsch auch als Bedarfsauswertung bezeichnet. Das bedeutet, dass nicht jeder Ausdruck einer Funktion ausgewertet wird. Nur wenn dieser tatsächlich im Programm benötigt wird, kommt es zu einer entsprechenden Berechnung. Diese Vorgehensweise führt zu einer deutlich effizienteren Ausführung der Programme.

Haskell Compiler

Genau wie bei jeder anderen Programmiersprache ist es auch bei der Arbeit mit Haskell notwendig, den Programmcode in die Maschinensprache zu übersetzen. Hierfür kommt häufig ein Compiler zum Einsatz, der ein ausführbares Programm erzeugt. Darüber hinaus gibt es interpretierte Programmiersprachen. Hierbei wird der Code erst während der Laufzeit übersetzt. Bei Haskell ist es möglich, beide Vorgehensweisen zu verwenden.

Es gibt viele verschiedene Haskell-Compiler. Besonders weit verbreitet ist der Glasgow Haskell Compiler (GHC). Dieser bietet zwei verschiedene Anwendungsmöglichkeiten. Zum einen können Sie ein Programm in Haskell schreiben und dieses dann in einer eigenen Datei abspeichern. GHC kompiliert diese dann und ermöglicht die Ausführung. Alternativ dazu können Sie GHC auch direkt über die Konsole aufrufen und die Programmbefehle hier eingeben. Das bietet sich insbesondere dazu an, kleinere Programmteile schnell und einfach auszuprobieren.

Wenn Sie die unten aufgeführten Beispiele in Haskell selbst ausprobieren möchten, ist es selbstverständlich notwendig, einen Haskell-Compiler zu installieren. Anweisungen hierfür finden Sie unter dem folgenden Link: https://www.haskell.org/downloads/.

Einige Beispiele für die Programmierung in Haskell

Um Haskell zu verstehen, ist es wichtig, einige Programmbeispiele zu geben. Wenn Sie sich bereits mit imperativen Programmiersprachen befasst haben, wird der Unterschied zwischen den verschiedenen Vorgehensweisen dabei schnell deutlich. Daher ist es sinnvoll, die hier vorgestellten Programme genau zu betrachten und sich zu überlegen, wie man eine entsprechende Aufgabe mit einer imperativen Programmiersprache umsetzen könnte.

Ein Hallo-Welt-Programm in Haskell

Wenn Sie beginnen, eine Programmiersprache zu erlernen, steht am Anfang fast immer ein Hallo-Welt-Programm. Dieses dient dazu, eine einfache Textausgabe über die Konsole auszugeben. Es erfüllt daher eine möglichst einfache Aufgabe. Das Programm dient lediglich dazu, die grundsätzlichen Strukturen der entsprechenden Programmiersprache aufzuzeigen. Daher beginnen wir auch unsere Beispiele für Programme in Haskell mit einem Hallo-Welt-Programm. Dieses besteht nur aus einer einzigen Zeile:

main = putStrLn ("Ein Programm in Haskell!")

Wenn Sie dieses Programm ausprobieren möchten, müssen Sie einen Texteditor aufrufen und die entsprechende Codezeile in einer Datei mit der Endung .hs abspeichern. Um es zu kompilieren, müssen Sie den Befehl ghc verwenden, um den Glasgow Haskell Compiler aufzurufen. Danach folgt das Flag -o und der Name der ausführbaren Datei, in der Sie das kompilierte Programm abspeichern möchten. Schließlich müssen Sie noch den Namen der Quelldatei angeben. Das Ergebnis dieses Programms ist in der folgenden Abbildung zu sehen. Das zeigt, dass diese Zeile ausreicht, um den entsprechenden Text auszugeben.

Hierbei definieren wir die main()-Funktion. Diese stellt in Haskell den Einstieg in das Programm dar. Darin rufen wir dann die Funktion putStrLn auf. Diese dient der Ausgabe von Zeichenketten. Daher können wir hier direkt den Text in Anführungszeichen angeben.

Zwar lässt sich das Programm auf diese Weise bereits problemlos ausführen. Allerdings ist es empfehlenswert, noch einige weitere Programmteile hinzuzufügen. Diese sind zwar nicht zwingend erforderlich. Allerdings entsprechen sie einem guten Programmierstil. Zum einen ist es sinnvoll, eine Typdefinition für die Funktion anzugeben. Diese sagt aus, welche Werte eine Funktion aufnimmt und welche Daten sie zurückgibt. In diesem Fall nimmt die Funktion keine Werte auf. Ihre Rückgabe besteht in einer Ausgabe über die Konsole – also in einer IO-Operation. Daher können wir die folgende Typdefinition verwenden:

C++ Programmieren für Einsteiger 14.99 € Verfügbar In den Warenkorb
main :: IO ()

Außerdem ist es sinnvoll, eine Angabe zum verwendeten Modul zu erzeugen. Wenn wir nur die main()-Funktion verwenden, ist dies zwar nicht erforderlich, da es sich hierbei um das Standard-Modul handelt. Dennoch entspricht es einem guten Programmierstil, diese Angabe vorzunehmen:

module Main (main) where

Diese zusätzlichen Vorgaben haben zwar keine Auswirkungen auf den Ablauf des Programms. Die Ausgabe bleibt daher genau die gleiche wie im obigen Beispiel. Allerdings erfüllt das Programm nun die Anforderungen an einen guten Programmierstil. Der komplette Code sieht dann so aus:

Eine Funktion in Haskell erstellen

Beim ersten Beispielprogramm waren kaum Unterschiede zu imperativen Programmen zu sehen. Um die verschiedene Vorgehensweise deutlich zu machen, erstellen wir im zweiten Beispiel nun jedoch eine Funktion. Daran kann man bereits deutlich besser erkennen, dass die Programmgestaltung in Haskell ganz anders abläuft als in C oder Java.

Die Funktion, die wir hierbei gestalten, soll lediglich die Aufgabe haben, zwei ganze Zahlen miteinander zu multiplizieren. Um sie zu erstellen, geben wir zunächst ihren Namen an. Danach führen wir die Variablen für die Eingabe auf. Diese trennen wir lediglich durch ein Leerzeichen. Nach einem Gleichheitszeichen geben wir an, wie das Ergebnis aussehen soll. Dabei können wir auf die Variablen, die wir für die Eingabe verwendet haben, zugreifen. Eine Funktion, die zwei Werte multipliziert, könnte so aussehen:

multiplizieren x y = x * y

Die Eingabewerte der Funktion sind demnach x und y. Der Ausgabewert beträgt x * y. Das bedeutet, dass die Funktion die beiden Werte miteinander multipliziert. Wenn wir die Funktion dann aufrufen, müssen wir zunächst ihren Namen nennen. Danach können wir zwei beliebige Werte angeben – jeweils durch ein Leerzeichen getrennt. Um dies zu demonstrieren, müssen wir zunächst wieder die main()-Funktion gestalten. Um das Ergebnis über die Konsole auszugeben, verwenden wir die print()-Funktion. Während die oben verwendete putStrLn-Funktion nur für Zeichenketten geeignet ist, lassen sich mit der print()-Funktion beliebige Werte ausgeben – wie etwa der Rückgabewert einer Funktion. Der Ausgabebefehl sieht demnach so aus:

main = print (multiplizieren 2 5)

Damit lässt sich das Programm bereits ausführen. Wenn wir wieder alle optionalen Bestandteile wie etwa die Typdefinitionen hinzufügen, sieht das Programm wie folgt aus:

Quicksort-Algorithmus mit wenigen Programmzeilen

Das dritte Beispiel soll aufzeigen, wie einfach die Programmerstellung mit einer funktionalen Programmiersprache sein kann. Hierfür erstellen wir ein Programm, das eine Liste nach dem Quicksort-Algorithmus sortiert. Wie dieser aufgebaut ist, haben wir bereits in einem eigenen Artikel beschrieben. Wenn Sie sich für den Ablauf des Programms interessieren, ist es empfehlenswert, den entsprechenden Artikel zu lesen.

Darin haben wir ein Beispielprogramm für den Quicksort-Algorithmus in der Programmiersprache C erstellt – also in einer imperativen Programmiersprache. An dieser Stelle ist es nicht wichtig, den kompletten Programmaufbau nachzuvollziehen. Sie sollten lediglich die Länge des entsprechenden Codes in der Programmiersprache C beachten. Wenn man alle Leerzeilen abzieht, bleiben 49 effektive Codezeilen für die Umsetzung dieses Algorithmus. Als Vergleich dazu nun der Quicksort-Algorithmus in Haskell:

Mit einer funktionalen Vorgehensweise haben wir den kompletten Quicksort-Algorithmus in nur sieben Zeilen erzeugt. Dabei haben wir zwar die optionalen Bestandteile weggelassen. Doch selbst wenn wir diese hinzufügen, wird der Code nur unwesentlich länger. An dieser Stelle ist es nicht möglich, alle Einzelheiten des Programmcodes zu erklären. Das Beispiel soll lediglich dazu dienen, zu verdeutlichen, wie effizient sich manche Aufgaben mit einer funktionalen Programmiersprache erledigen lassen. Insbesondere für die Gestaltung rekursiver Funktionen ist hierbei nur sehr wenig Code erforderlich.

Ähnliche Produkte

Schreibe einen Kommentar