APL (A Programming Language) ist eine üblicherweise interpretierte Programmiersprache, deren Syntax überwiegend aus Symbolen besteht. Sie wurde von Kenneth E. Iverson und seinen KollegenFalkoff, A.D., K.E. Iverson, The Design of APL, IBM Journal of Research and Development, Volume 17, Number 4, 1973-07. bei IBM in den 1960er Jahren als algorithmische Notation (u. a. für den Mathematikunterricht)Iverson K.E.," (PDF; 2,2 MB)", Communications of the ACM, 23: 444-465 (August 1980). und als Entwurfssprache für Großrechner entwickelt.
Geschichte mini|IBM 5100 Mikrocomputer mit APL-Tastatur Mit dem Buch A Programming Language aus dem Jahr 1962 gab Kenneth Iverson den Anstoß zur Verwendung eines neuen Konzepts in der Programmierung. Bevor der erste Interpreter verfügbar war, diente APL bereits als Metasprache für die Beschreibung der Architektur des damals neu entwickelten Computersystems IBM System/360 aus der Sicht des Programmierers.A. D. Falkoff, K. E. Iverson, E. H. Sussenguth: A formal description of SYSTEM/360. In: IBM Systems Journal. Volume 3, Issue 2 (1964). Ab 1965 wurde APL als Programmiersprache auf Großrechnern (z. B. IBM System/360) implementiert und den Kunden als Timesharing-Option angeboten. Zu jener Zeit wurden IBM-Kugelkopf-Schreibmaschinen als „Terminal“ verwendet. Daher hatte der ursprüngliche Zeichensatz nur (kursive) Großbuchstaben.Die Schreibmaschine hat einen begrenzten Zeichenvorrat. Spezielle Symbole wurden deshalb durch Übereinandertippen zweier Zeichen erzeugt. Beispiel: Das Zeichen ⍝ wird durch die Folge ⋂ [Rücktaste] ° erzeugt.
Ab 1975 gab es eine Implementierung auf der IBM 5100, einem Vorläufer des PC, der bereits ein Mikrocomputer war. Obwohl die Maschine nach damaligen Maßstäben als durchaus leistungsfähig galt, lief APL auf ihr verhältnismäßig langsam, da es sich um eine Emulation des Mainframe-APL-Interpreters handelte.
Die ersten Implementierungen auf PCs benötigten ein Spezial-EPROM, damit der APL-Zeichensatz angezeigt werden konnte. Der APL-Zeichensatz wurde ursprünglich so gewählt, dass die Symbole möglichst selbsterklärend sind, dass sich also die Funktionen aus den Symbolen intuitiv herleiten lassen. Seit einigen Jahren wird der Begriff APL auch als Array Processing Language interpretiert.
Besonderheiten
Operatoren und spezielle Zeichen APL verwendet spezielle Operatoren, bzw. Befehle, die jeweils die Funktion haben, nicht nur einzelne Zahlen-Werte zu bearbeiten, sondern bei Bedarf ganze Vektoren und Matrizen, z. B. 2 Matrizen zu addieren oder das Skalar-Produkt von 2 Vektoren zu berechnen. Für jeden dieser Operatoren gab es ein spezielles Zeichen, wodurch insgesamt ein erweiterter Zeichensatz benötigt wurde, und zwar sowohl auf der Tastatur, im Speicher und auf dem Bildschirm – seitdem es solche gab – wie auch auf dem Drucker. Es gab damals noch keine Laser- oder Inkjet-Drucker, die man programmieren kann, quasi jedes beliebige Zeichen zu generieren. Die Verwendung solcher Zeichen mit der Funktion von Operatoren ermöglichte zwar einen extrem knappen, aber für Außenstehende auch kryptischen Code, der viele Leute abschreckte und nicht zwingend war. Man hätte auch reservierte Worte als Operatoren verwenden können. Inzwischen findet man solche Zeichen im Unicodeblock Verschiedene technische Zeichen.
Interaktivität APL war von Anfang an interaktiv: Nach der Eingabe eines Befehls (z. B. einer Rechenanweisung 1234 − 777) drückt man die Entertaste, der Befehl wird vom Interpreter ausgeführt und das Ergebnis angezeigt. Eine spezielle Anweisung für die Ausgabe des Ergebnisses, wie z. B. der PRINT-Befehl in BASIC, ist nicht nötig, existiert aber für den Fall, dass ein Ergebnis angezeigt werden soll, das normalerweise nicht angezeigt würde (z. B., wenn einer Variablen ein Wert zugewiesen wird).
Tritt ein Fehler auf, erhält man eine entsprechende Meldung. Man kann seine Eingabe modifizieren und erneut ausführen. Die dadurch mögliche direkte Interaktion mit dem Computer ist bis heute einer der großen Vorteile von APL als Entwicklungswerkzeug.
Aus heutiger Sicht klingt dies trivial, aber APL war eine der ersten Programmiersprachen, die diesen Luxus bot: Konkurrierende Sprachen waren noch nicht interaktiv, sondern mussten vor der Ausführung eines Programms jeweils kompiliert werden.
Programmcode Folgen von Befehlen lassen sich zu Funktionen zusammenfassen. Funktionen können wiederum andere Funktionen aufrufen. In der Tat ist APL eine der ersten funktionalen Programmiersprachen. Näheres und ein Beispiel siehe unten.
Bis in die 1990er Jahre fehlten APL die Kontrollstrukturen der „Strukturierten Programmierung“. Logik musste durch Sprunganweisungen realisiert werden. In APL werden Kontrollstrukturen seltener als in anderen imperativen Programmiersprachen verwendet, einerseits weil APL-Funktionen nicht nur Skalare, sondern Datenstrukturen beliebiger Dimension verarbeiten, andererseits, weil es den Operator Each bietet.
Datentypen APL kennt mindestens die Datentypen Char, Bool, Int und Float, allerdings muss der Programmierer dies nicht berücksichtigen, denn der Interpreter wandelt die Datentypen automatisch um, wann immer dies notwendig ist. Dies bedeutet auch, dass APL keine Typprüfung kennt.
Der Datentyp von Variablen muss nicht eigens deklariert werden, man kann einer Variablen eine Gleitkommazahl zuweisen (oder einen Vektor oder eine Matrix von Gleitkommazahlen) und danach einen Text, ohne dass es zuvor einer besonderen Anweisung bedarf.
Speicherverwaltung Auch die Speicherverwaltung wird vom Interpreter übernommen. Ein APL-Programmierer muss sich während des Programmablaufs weder um das Reservieren noch um das Freigeben von Speicher kümmern. Der Arbeitsspeicher wird im sogenannten Workspace für Variablen und Programme insgesamt zur Verfügung gestellt, er kann beim Programmstart festgelegt und in manchen APL-Produkten auch dynamisch erweitert werden.
Array-Verarbeitung Fast alle Funktionen in APL sind auch nicht-skalar ausgelegt. Dies bedeutet, dass Funktionen nicht nur auf einzelne Skalare (Zahlen oder Characters), sondern auch auf Vektoren (Zahlenreihen), Matrizen (Tabellen) und mehrdimensional angeordnete Daten (Arrays) sowie auf Listen angewendet werden können.
Beispiele (die eingerückte erste Zeile ist die Benutzereingabe, die zweite Zeile die Antwort des APL-Interpreters)
Viele Programmiersprachen erlauben die Addition zweier Skalare: 2 + 3 5
APL gestattet aber auch die Addition Vektor und Skalar: 2 3 4 + 3 5 6 7
und die Addition zweier Vektoren: 2 3 4 + 5 6 7 7 9 11
Ausführung und Rangfolge Es gibt in APL nur eine einzige Rangfolgenregel: Alles wird von rechts nach links abgearbeitet. Ausnahme: Ausdrücke in Klammern werden zuerst abgearbeitet. Daher gilt: 10×2+3 50 aber: (10×2)+3 23
Variablen In APL müssen Variablen nicht deklariert oder typisiert werden (siehe Datentypen). Eine Variable wird erzeugt, indem man einen Namen, gefolgt von einem Zuweisungspfeil (←), gefolgt vom Wert bzw. den Werten der Variablen eingibt: XWERT←456.78 YVECT←56 23 81.8 796 0.014 8.9 20 1 TEXT1←'Dies ist ein Text' MATRIX←2 4ρYVECT (der Operator ρ, genannt rho, verwandelt den 8-gliedrigen Vektor YVECT in eine Matrix mit 2 Zeilen und 4 Spalten. So lassen sich auch Arrays mit mehr Dimensionen bilden.)
Das Konzept der Konstanten, also unveränderbar deklarierter Werte, gibt es in APL nicht, es kann aber simuliert werden durch eine Funktion, die keine Argumente benötigt und ein explizites Ergebnis zurückliefert.
Geltungsbereich Jede Zuweisung erzeugt eine globale Variable, d. h. die Variable ist im gesamten Programm sicht- und änderbar. Man kann den Geltungsbereich von Variablen aber einschränken, indem man den Namen der Variablen in die Kopfzeile einer Funktion aufnimmt. Eine solche Variable wird als lokal bezeichnet, da sie nur zur Laufzeit der Funktion sichtbar ist.
Wenn allerdings eine Funktion F1 eine lokale Variable A definiert und anschließend eine Funktion F2 aufruft, dann ist A innerhalb von F2 sicht- und änderbar, was heute als Designmakel gilt. Die Direct Functions in Dyalog APL verhalten sich allerdings anders: Dort sind lokale Variablen tatsächlich im engeren Sinne lokal und auch in aufgerufenen Funktionen unsichtbar.
Arrays Daten jeder Art werden in APL Arrays genannt. Arrays können unterschiedliche Dimensionen haben. Ein einzelner Wert wird Skalar genannt. Mehrere Werte nebeneinander bilden einen Vektor. Der Operator zur Verkettung (Konkatenieren) mehrerer Skalare ist das Komma. Dabei ist es auch möglich, einen einzelnen Wert mit einer Leeren Menge zu verketten und so einen Vektor zu erhalten, der aus einem einzigen Element besteht. Auch leere Vektoren sind erlaubt: Das sind Vektoren, die überhaupt kein Datenelement enthalten, sondern nur die Strukturinformation.
Werte, die in Zeilen und Spalten angeordnet sind, bilden Tabellen, auch Matrizen oder zweidimensionale Arrays genannt.
Die Dimension eines Arrays wird in APL mit dem griechischen Buchstaben ρ (Rho) angegeben. Wenn von dem „Rank“ eines Arrays die Rede ist, meint man die Anzahl der Dimensionen des Arrays, also Rho von Rho. Demzufolge ist der Rank eines Skalars 0, der eines Vektors 1, der einer Tabelle 2, und so weiter.
Die Ebenen eines dreidimensional angeordneten Arrays heißen Planes. Es sind Arrays mit n Dimensionen möglich, die Anzahl ist nur begrenzt durch die maximale Größe der Integer-Indizierung (231-1) und den zur Verfügung stehenden Speicherplatz. mini|Ein „Nested Array“ in APL2
Im Jahre 1986 brachte IBM ein erheblich erweitertes APL mit dem Namen APL2 auf den Markt. Die Erweiterung bestand hauptsächlich darin, dass jedes Element eines Arrays aus beliebigen anderen Datenstrukturen bestehen kann (Nested Array). Damit ergeben sich verschachtelte Strukturen. Zur Veranschaulichung befindet sich rechts ein Beispiel. Es handelt sich dabei um eine bereits behandelte, numerische Matrix mit 4 Zeilen und 5 Spalten. Jedoch besteht das 2. Element der 2. Zeile aus einem Textvektor und das 4. Element der 3. Zeile aus einer 2x2-Matrix. Es lassen sich somit auch die Textlabels mit den numerischen Werten zu einer Tabelle verknüpfen. APL2 eröffnete die Möglichkeit, auch mixed arrays sowie einfache und komplexe Listen zu erzeugen.
Im Zuge dieser Erweiterung wurden auch neue sogenannte „primitive Funktionen“ (primitive functions) zur Bearbeitung der neuen Datenstrukturen eingeführt sowie die alten Funktionen angepasst und in ihrem Geltungsbereich erweitert. Andere APL-Hersteller brachten ähnliche Erweiterungen ihrer Implementierungen heraus, wobei feine Unterschiede die Portierung eines Programms zu einer anderen Implementierung erschweren. Heute gilt die APL2-Implementation als Referenz für alle Hersteller, man bemüht sich um größtmögliche Kompatibilität.
Funktionen und Operatoren APL kennt sowohl Funktionen als auch Operatoren, aber die Bedeutung der Begriffe ist anders als in der Mathematik: Funktionen werden auf Daten angewendet, Operatoren auf Funktionen und Daten. Funktionen liefern Daten zurück, Operatoren sogenannte „abgeleitete Funktionen“ (engl.: ).
Beispiel
Das Zeichen slash (/) steht für den Operator reduce. Operatoren erwarten einen oder zwei Operanden. Wird nur ein Operand verwendet, dann muss er links neben dem Operator stehen:
+/
In diesem Beispiel ist der Operand die Funktion „Plus“. Zusammen mit dem Operator wird die abgeleitete Funktion Summiere gebildet.
Angewendet auf einen Vektor:
+/ 3 4 5
bewirkt der Operator Reduce, dass der Operand zwischen die einzelnen Bestandteile des Vektors eingefügt wird. Abstrakt ausgedrückt:
f/ n1 n2 n3 == n1 f n2 f n3
und im konkreten Beispiel (das Ergebnis steht darunter):
+/ 3 4 5 == 3 + 4 + 5 12