fit 2002 > Programmiersprachentypen > Entstehungskontext > Funktionale Sprachen

Überblick


Die funktionale Programmierung beruht, wie der Name schon verrät, auf Mathematik und Logik. Die Programme werden nicht konkret auf Maschinen bezogen, sondern auf einem abstrakten, mathematischen Niveau formuliert. Sie sind im Gegensatz zu den imperativen Sprachen eine Ein-/Ausgaberelation, die im Programmtext direkt als Funktionen geschrieben werden. Die Programme sind "zeitlos", hängen also nicht vom aktuellem Zustand der Maschine ab.

Funktionale Programmiersprachen wie LISP, MIRANDA etc. zeichnen sich dadurch aus, daß sie auf einer rein mathematischen Theorie fundieren. Die Programmierung erfolgt in diesen Sprachen rechnerunabhängig auf einem höheren Abstraktionsniveau. In der funktionalen Programmiersprachen ist ein Programm eine Ein-/ Ausgaberelation, d.h., sie ist eine Abbildung von Eingabedaten auf zugehörige Ausgabedaten. Das in der funktionalen Programmiersprache geschriebene Programm liefert zu jedem Zeitpunkt ein und das selbe Ergebnis und ist somit "zeitlos".

Ursprüngliche Fragestellung

Seit den fünfziger Jahren werden Programmiersprachen unterschiedlicher Konzepte und Stile entwickelt und angewendet. Je nachdem welche Verfahrensklassen bzw. Maschinenarchitekturen zugrunde gelegt werden, sind verschiedene Sprachkonstrukte und Programmierparadigmen entstanden.

Logische und funktionale Programmiersprachen werden zusammenfassend häufig auch als deklarative Sprachen bezeichnet. Obwohl erste Ansätze zu funktionalen Sprachen mit LISP bereits vor 1960 als Listenverarbeitungssprachen mit imperativen Bestandteilen eingeführt wurden, entstanden deklarative (rein funktionale bzw. logische) Sprachen in den 70er Jahren im Zusammenhang mit der sogenannten Softwarekrise. Einerseits war die Komplexität der zu implementierenden Verfahren so stark gestiegen, daß der Entwicklungsaufwand der imperativen Programme unvertretbar hoch und die Programme selbst nicht mehr vollständig prüfbar waren. Insbesondere die Softwaresicherheit war nicht zu gewährleisten. Deshalb wurden Sprachen untersucht, deren Programme korrekt spezifizierbar und verifizierbar sein sollten. Damit entstanden die deklarativen Sprachen. Daneben wurde die Objektorientierung einge-führt, bei der Datentypen und Aktionen als Bestandteile eines Objektes zusammengefaßt wurden. Gegenwärtig besteht der Trend funktionale und logische Bestandteile in einer deklarativen Sprache zu vereinigen und dabei auch Objektorientierung zu berücksichtigen.

Vorgeschichte (Reaktion auf was)

Die funktionale Programmierung war lange Zeit wegen der Beweisbarkeit, Klarheit usw. in akademischen Kreisen hoch angesehen. Allerdings war ihre Umsetzung auf existierenden Computern extrem ineffizient. Einer der Gründe, warum funktionale Programmierung inzwischen angewandt wird, ist in neueren Entwicklungen im Hardwarebereich zu suchen. Früher war die Herstellung von Prozessoren sehr teuer, was nicht mehr in so hohem Maße der Fall ist. Um die Rechenleistung eines Computersystems zu erhöhen, setzt man unter anderem auch parallel geschaltete Prozessoren ein. Um die Möglichkeiten der parallel geschalteten Prozessoren voll ausschöpfen zu können braucht man eine Programmiersprache, die nicht sequentiell aufgebaut ist, sondern so, daß die zu lösenden komplexen Problemstellungen so beschrieben werden, daß eine gleichzeitige Lösung der Problemstellungen möglich ist. Funktionale Programmiersprachen sind für den Einsatz von solchen parallel geschalteten Prozessoren sehr geeignet. Ein anderer Grund ist der Wunsch Spezifikationen für die Programme präziser zu machen, um die Entsprechung zwischen dem Programm und seiner Spezifikation besser in den Griff zu bekommen. Dieser Wunsch beruhte auf der Erkenntnis, daß etwa 50% der Arbeitsanstrengungen eines Programmierers in die Behebung von oft tiefsitzenden, schwer auffindbaren Fehlern der Programme gehen. Aus diesem Grund war man auf der Suche nach einer eindeutigen Programmiersprache für die Spezifikation. Dabei bot sich eine aus der Mathematik stammende Programmiersprache als beste Lösung an. Auf diese Art kann dann der Zusammenhang zwischen Programm und Spezifikation mathematisch bewiesen werden. Ein großes Hindernis für den Einsatz mathematischer Methoden beim Programmieren ist der Gebrauch der Variable als ein benannter Speicherplatz, dessen Inhalt über Zuweisungen verändert werden kann. Um sagen zu können, wofür eine solche Variable steht, muß man wissen, an welchem Punkt des Programmablaufs man sich befindet. Eine mathematische Variable dagegen hat einen Wert. Wenn dieser Wert noch nicht berechnet wurde, ist diese Variable unbekannt und hat nicht irgendeinen anderen Wert. In den funktionalen Programmiersprachen haben solche Variablen diese, unter dem Namen referenzielle Transparenz bekannte, Eigenschaft. Diese hat neben der mathematischen Beweisbarkeit noch einen weiteren Vorteil. Da die unbekannten Variablen eines Ausdrucks ganz einfach nicht ausgewertete Funktionsaufrufe sind, die erst dann bekannt werden, wenn die Funktion ausgewertet wird, wird der Unterschied zwischen Funktion ( Code ) und Variablen ( Daten ) aufgehoben. Dies führt zu Funktionen höherer Ordnung und somit auch dazu, daß der Programmierer Funktionen und Daten mit gleicher Leichtigkeit manipulieren und strukturieren kann.

Ein funktionales Programm entspricht im wesentlichen einer Funktion im mathematischen Sinne, die auf die Eingabewerte angewendet wird und den Funktionswert als Ausgabe liefert. Der Lambda-Kalkül (l-Kalkül) von Church und seine Theorie bilden die mathematische Basis der funktionale Programmierung. Auf Grund dieser mathematischen Tradition haben funktionale Programmiersprachen eine verhältnismäßig einfache Semantik, die eine wichtige Grundlage für Korrektheitsbeweise bildet. In diesem Zusammenhang ist auch die Eigenschaft der "referential transparency" zu nennen: Der Wert eines Ausdruckes hängt nur von seiner Umgebung, nicht aber vom Zeitpunkt seiner Auswertung ab. In einem funktionalem Programm kann ein Teilausdruck also immer durch einen anderen Ausdruck der den selben Wert hat, ersetzt werden. Die Semantik des Programms bleibt unverändert. Der Programmentwurf erfolgt in einer funktionalen Sprache auf einer höheren Abstraktionsstufe als in einer imperativen Sprache.

In seiner Einleitung kritisiert John Backus die damals konventionellen Programmiersprachen als "...das Reich derer, die sich mit Anhäufungen von Details auseinandersetzen, anstatt um neue Ideen zu ringen". Ihm erscheinen die Diskussionen über Programmiersprachen " ...wie mittelalterliche Debatten über die Anzahl der Engel, die auf einer Nadelspitze tanzen können." 2 Man verbeiße sich in unsinnige Details, anstatt über grundsätzlich unterschiedliche und neue Konzepte zu streiten. Zwar hätten viele kreative Informatiker "elegante" neue Methoden entwickelt, die sie jedoch auf die Analyse der konventionellen Programmiersprachen "verschwendet" hätten, anstatt ihre Energie auf die Erfindung von etwas Neuem zu verwenden. Beim Lesen dieses Textes entsteht leicht der Eindruck, daß Backus, der wie viele Vertreter der Funktionalen Programmierung, ursprünglich Mathematiker war, durch die Formen, die sich in der konventionellen Programmierung entwickelt hatten, in seinem ästhetischen Empfinden beleidigt fühlte. Der Ironische Stil im Abschnitt "Conventional Programming Languages: Fat and Flabby" läßt darauf schließen. Ein konkretes Beispiel dafür ist der schon oben aufgeführte Satz " ...wie mittelalterliche Debatten über die Anzahl der Engel, die auf einer Nadelspitze tanzen können."

Nach John Backus beruht jede Programmiersprache auf einem Modell eines Computersystems. Für die funktionale Programmiersprachen entwarf er ein Modell, welches er nach seinen Vorstellungen entsprechend in Kriterien unterteilte. John Backus klärt uns nicht darüber auf , was er unter den Grundlagen eines Modells versteht. Es ist aber herauszulesen, daß es ihm im Wesentlichen darum geht, daß die Grundlagen des Modells mathematisch beweisbar sind. Dies waren die Kriterien für das Modell von John Backus für eine funktionale Programmiersprache:
Grundlagen
Hierbei ging es ihm darum, ob es eine elegante, kurze mathematische Beschreibung existiert.

History sensitivity
Dies bedeutet, ob das Programm Informationen speichern kann, welche die nachfolgenden Programme beeinflussen.

Semantik
Sind Zustände einfach oder kompliziert, d.h.: Ist ein Programm so geschrieben, daß man den Wert einer Variablen auf Anhieb bzw. nach kurzem Nachvollziehen erkennt oder nicht.

Klarheit
Sind die Programme mit ihren Befehlen ein klarer Ausdruck des Rechenprozesses? Gibt es eindeutige Begriffe innerhalb des Programms, die uns helfen, über den Rechenprozeß zu argumentieren?
Die konventionellen Programmiersprachen können zwar einigermaßen klar sein, jedoch sind sie von der begrifflichen Seite her nicht zu gebrauchen. Konventionelle Programmiersprachen orientieren sich am "von Neumann Computer", der, in den Worten von John Backus, um ein Flaschenhals herumgebaut ist. Die CPU und der Speicher sind durch eine Leitung miteinander verbunden. Die CPU und der Speicher tauschen ihre Daten miteinander mit Hilfe dieser Leitung, der ein "schmales Rohr" zwischen beiden bildet, da es nur eine Informationseinheit pro Zeiteinheit durchläßt. Dies beeinflußt natürlich den Programmierstil. Ein weiteres Problem der "von Neumann Computer" liegt darin, daß der Aufbau des Programms zwar klar sein kann , die Begriffe innerhalb des Programms jedoch nicht eindeutig bestimmt sind.

John Backus kommt zu dem Schluß, daß Beweise in jedem Fall nur mittels der Sprache der Logik über Programme argumentieren, diese jedoch nicht direkt miteinbeziehen können. Seine Idee besteht darin, daß eine Programmiersprache eine ihr assoziierte Algebra, also im Falle der funktionalen Programmiersprachen Rechenregeln für Funktionale ( Funktionen höherer Ordnung ) und Funktionen, besitzen sollte, so daß mit den Programmen ähnlich wie beim Auflösen einer Gleichung algebraisch bewiesen werden kann. John Backus hat diesen Vortrag "Can Programming Be Liberated from the von Neumann Style?" 1978 gehalten. In den 80`er Jahren entstand eine Reihe von funktionalen Programmiersprachen, die von HOPE bis zu HASKELL, GOFER und OPAL reichen. Die in dem Text von Backus skizzierten Grundkonzepte stimmen jedoch bei all diesen Sprachen überein. Es wird von den Vertretern der Funktionalen Richtung behauptet, daß die Funktionalen Programmiersprachen tatsächlich einen klaren eleganten Programmierstiel ermöglichen und darüber hinaus die Beweisbarkeit der Programme erhöhen. In einer Funktionalen Programmiersprache kann man leichter und schneller schreiben. Für Anfänger ist jedoch die funktionale Programmiersprache, die sehr viele rekursive Programme enthält, sehr viel schwerer nachzuvollziehen, als zum Beispiel ein PASCAL Programm.

Anwendung der Funktionale Sprache

  • Künstliche Intelligenz
    • Projekt Cyc: Wissensbasis in Common Lisp, 1985.
  • Genetic Programming
  • Optimierung von Computerprogrammen mit genetischen Algorithmen
  • Einsatz als Prototyping-Sprache
  • Erweiterungssprache für große Softwaresysteme
    • AutoCAD bis Version 12/13
    • Unix-Editor (X)Emacs.
    • Grafikprogramm GIMP

Weiterführende Informationen


>[reasons]
Why Functional Programming Matters (paper)
>[lisp]
Lisp history

>Entstehungskontext | Konzepte und Techniken | Entwicklung und Auswirkungen | Praxis | Bewertung