Funktionale Programmierung: Erklärung & Beispiel
Gängige Programmiersprachen lassen in der Regel verschiedene Programmierparadigmen zu, wobei grob zwischen der deklarativen Programmierung und der imperativen Programmierung unterschieden wird. Bei solchen Paradigmen handelt es sich – vereinfacht gesagt – um die grundlegende Herangehensweise bei der Programmierung einer Software. Ein Unterform des deklarativen Ansatzes ist die sogenannte funktionale Programmierung, die insbesondere bei der Entwicklung folgender Programme bzw. Codes genutzt wird:
- technische und mathematische Anwendungen
- Künstliche Intelligenz (KI)
- Compiler und Parser
- Algorithmen
Was ist funktionale Programmierung?
Der Name lässt es bereits vermuten: Im Mittelpunkt der funktionalen Herangehensweise beim Programmieren stehen Funktionen. Bei einem funktionalen Programm können alle Elemente als Funktion aufgefasst und der Code kann durch aneinandergereihte Funktionsaufrufe ausgeführt werden. Im Umkehrschluss gibt es keine eigenständigen Zuweisungen von Werten. Eine Funktion stellt man sich dabei am besten als besondere Variante eines Unterprogramms vor. Dieses ist wiederverwendbar und gibt, anders als eine Prozedur, direkt ein Resultat zurück.
Natürlich gibt es in vielen höheren Programmiersprachen Funktionen, die definiert und dann angewendet werden. Dies ist also noch nicht das Besondere an der funktionalen Programmierung. Was den funktionalen Ansatz so wichtig für die Informatik und gleichzeitig so vielfältig einsetzbar macht, ist die Tatsache, dass Funktionen innerhalb dieses Programmierparadigmas verschiedene „Gestalten“ annehmen können. Sie können beispielsweise – wie Daten – miteinander verknüpft werden. Ferner ist die Verwendung als Parameter sowie die Nutzung als Funktionsergebnis möglich. Diese spezielle Behandlung der Funktionen erlaubt Programmierern die Implementierung und Verarbeitung von weitreichender Berechnungsaufgaben (insbesondere solcher von symbolischer Natur).
Natürlich gibt es in vielen höheren Programmiersprachen Funktionen, die definiert und dann angewendet werden. Dies ist also noch nicht das Besondere an der funktionalen Programmierung. Was den funktionalen Ansatz so wichtig für die Informatik und gleichzeitig so vielfältig einsetzbar macht, ist die Tatsache, dass Funktionen innerhalb dieses Programmierparadigmas verschiedene „Gestalten“ annehmen können. Sie können beispielsweise – wie Daten – miteinander verknüpft werden. Ferner ist die Verwendung als Parameter sowie die Nutzung als Funktionsergebnis möglich. Diese spezielle Behandlung der Funktionen erlaubt Programmierern die Implementierung und Verarbeitung von weitreichender Berechnungsaufgaben (insbesondere solcher von symbolischer Natur).
Warum die funktionale Programmierung heute relevanter ist denn je
Obwohl die Wurzeln der funktionalen Programmierung bis in die 1930er-Jahre zurückreichen (als Teil der mathematischen Grundlagenforschung), erfreut sich die funktionale Herangehensweise immer noch großer Beliebtheit, vor allem im technischen und mathematischen Bereich. Dafür gibt es gleich mehrere Gründe:
Es gibt also zahlreiche praktische Gründe, warum die funktionale Programmierung und die mit diesem Prinzip arbeitenden funktionalen Programmiersprachen bis heute eine besondere Stellung innerhalb der Informatik einnehmen, vor allem, wenn es um komplexe mathematische Aufgabenstellungen und Algorithmen geht. Gleichzeitig sorgen die sehr speziellen Anwendungsgebiete dafür, dass funktionale Programmiersprachen so etwas wie ein Nischendasein führen.
- umfangreiche Möglichkeiten zur algebraischen Programmtransformation
- umfangreiche Möglichkeiten zur algebraischen Programmsynthese
- einfache semantische Analyse-Möglichkeiten dank des Verzichts auf „innere Zustände im Berechnungsprozess“ und „Seiteneffekte“.
- Wegfall innerer Zustände: Es sind, anders als bei der imperativen Programmierung, keine inneren Zustände eines Berechnungsprozesses erforderlich.
- Verzicht auf Seiteneffekte: Auch auf die zu den inneren Zuständen gehörenden Zustandsänderungen, die sogenannten Seiteneffekte, kann beim funktionalen Arbeiten verzichtet werden.
Es gibt also zahlreiche praktische Gründe, warum die funktionale Programmierung und die mit diesem Prinzip arbeitenden funktionalen Programmiersprachen bis heute eine besondere Stellung innerhalb der Informatik einnehmen, vor allem, wenn es um komplexe mathematische Aufgabenstellungen und Algorithmen geht. Gleichzeitig sorgen die sehr speziellen Anwendungsgebiete dafür, dass funktionale Programmiersprachen so etwas wie ein Nischendasein führen.
Auf einen Blick: Die wichtigsten funktionalen Programmiersprachen
Zu den wichtigsten Programmiersprachen, die auf dem funktionalen Ansatz basieren, zählen folgende Vertreter:
- LISP
- ML
- Haskell
- OCaml
- F#
- Erlang
- Clojure
- Scala
- Perl
- Ruby
- Visual Basic .NET
- Dylan
- ECMAScript
Vor- und Nachteile funktionaler Programmierung im tabellarischen Überblick
Vorteile | Nachteile |
---|---|
Programme sind zustandslos | Daten (z. B. Variablen) sind nicht veränderbar |
Gut für die Parallelisierung geeignet | Abruf großer Datenmengen nicht effizient möglich |
Leicht testbarer Code | Nicht empfehlenswert für Verbindungen zu Datenbanken und Servern |
Leicht verifizierbarer Code, selbst zustandslose Funktionen lassen sich verifizieren | Nicht geeignet für viele Rekursionen desselben Stacks |
Lässt sich gut mit imperativer, objektorientierter Programmierung kombinieren | Rekursive Programmierweise kann zu schwerwiegenden Fehlern führen |
Präziserer, kürzerer Code | Nicht für alle Aufgaben geeignet |
Die Tabelle gibt einen guten Überblick darüber, ob das funktionale Paradigma der passende Ansatz für die Programmierung eines Softwareprojekts ist oder nicht. Die Entscheidung zugunsten eines Programmierstils ist häufig aber auch stark von den persönlichen Vorlieben des Entwicklers abhängig. So steht bei vielen Programmierern beispielsweise auch die objektorientierte Programmierung als konkrete Alternative zur funktionalen Herangehensweise hoch im Kurs. Im Folgenden sollen die beiden Ansätze daher kurz miteinander verglichen werden – inklusive abschließendem Praxis-Beispiel.
Trend oder kein Trend? Objektorientierte und funktionale Programmierung im Quervergleich
Genau wie in der Mode gibt es auch beim Programmieren Trends: Seit geraumer Zeit ist das objektorientierte Programmieren – insbesondere bei der Entwicklung von Webanwendungen und Computerspielen – ziemlich populär. Im Vergleich zur funktionalen Programmierung beschreibt man bei diesem Ansatz die einzelnen Elemente nicht als Funktion, sondern als Objekte und Klassen. In Kombination mit einem Vererbungssystem hat dies den Vorteil, dass sich sämtliche Komponenten jederzeit und problemlos wiederverwenden und erweitern lassen. Funktionaler Code ist auf der anderen Seite wesentlich schlanker, übersichtlicher und insbesondere dort im Vorteil, wo testbarer und verifizierbarer Code benötigt wird.
Im Übrigen muss prinzipiell gar nicht unbedingt die Wahl zwischen objektorientierter und funktionaler Programmierung getroffen werden: Viele moderne Programmiersprachen unterstützen nämlich die Arbeit mit beiden Programmierstilen, sodass sich diese bequem miteinander kombinieren lassen und man von den Vorzügen beider Paradigmen profitieren kann.
Im Übrigen muss prinzipiell gar nicht unbedingt die Wahl zwischen objektorientierter und funktionaler Programmierung getroffen werden: Viele moderne Programmiersprachen unterstützen nämlich die Arbeit mit beiden Programmierstilen, sodass sich diese bequem miteinander kombinieren lassen und man von den Vorzügen beider Paradigmen profitieren kann.
Funktionale Programmierung am Beispiel eines Parsers
Parser sind zentrale Elemente für die Vielzahl aller Computerprogrammen. Als Vorarbeiter für Compiler, die Programmiersprache in Maschinensprache übersetzen, sind sie häufig unabdingbar.
Ein Parser lässt sich grundsätzlich auf Basis verschiedenster Programmierparadigmen umsetzen – beispielsweise auch mit einer objektorientierten Sprache. Der funktionale Ansatz bietet allerdings eine Reihe von nützlichen Vorteilen, wenn es um die Code-Gestaltung eines Parsers geht:
Ein Parser lässt sich grundsätzlich auf Basis verschiedenster Programmierparadigmen umsetzen – beispielsweise auch mit einer objektorientierten Sprache. Der funktionale Ansatz bietet allerdings eine Reihe von nützlichen Vorteilen, wenn es um die Code-Gestaltung eines Parsers geht:
- Es gibt keine globalen und veränderbaren Variablen. Entsprechend gibt es auch keine Programmierfehler, die aus dem sogenannten „mutable global state“ (dt. frei „Code-weiter, veränderbarer Zustand“) resultieren, wie es bei objektorientierten Projekte der Fall sein kann. Davon profitiert ein Parser als zentrales Programmelement.
- Dank Funktionen höherer Ordnung und dem überschaubaren Programmcode lassen sich auch größere Datensammlungen einfach bewältigen. Dies kommt einem Parser, der naturgemäß große Datenmengen verarbeiten muss, sehr zugute.
- Ein Parser ist ein Programmelement, das sehr häufig durchlaufen wird. Es hilft also dem Gesamtprogramm, wenn dieses zentrale Element präzise programmiert wird und entsprechend effizient abläuft, wie es bei der funktionalen Programmierung der Fall ist.
- Ein Fehler im Parsing-Prozess ist in der Regel fatal und muss möglichst vermieden werden. Während ein Programm läuft, entstehen aber zwangsläufig zahlreiche semantische Abhängigkeiten, die – allerdings oft erst nach längerer Laufzeit – zu schweren Fehlern führen können. Sauber umgesetzt kann funktionale Programmierung dabei helfen, solche schweren Fehler in der Ausführung zu minimieren beziehungsweise ganz zu verhindern.