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 macht den Programmierungsansatz bzw. funktionale Programmiersprachen für diese Art von Computeranwendungen so interessant? Und worin besteht der Unterschied zu anderen Konzepten wie beispielsweise der objektorientierten Programmierung?

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

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:

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

Funktionale Programmierung bietet ein hohes Maß an Abstraktion, denn sie basiert auf dem mathematischen Begriff und Prinzip der Funktion. Bei sauberer Anwendung führt diese Art des Programmierens zu sehr präzisem Code. Aus möglichst vielen kleinen, wiederholt nutzbaren und sehr spezialisierten Einheiten, den Funktionen, wird ein Programm zur Lösung einer wesentlichen größeren Aufgabe erstellt.

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

Darüber hinaus gibt es bekannte Programmiersprachen, die die funktionale Programmierung als eines von mehreren möglichen Paradigmen zulassen:

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

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:

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