PLACE
languages

APL

In 1957, Kenneth E. Iverson devised a notation for description and analysis of computing-related topics. A characteristic feature of that notation was the lavish and inventive use of arrays of arbitrary dimensions. Iverson used it for some time in his teaching to university students. As other people got interested in the formalism, they also began using it for teaching and reasearch. Thus a community emerged around the language, experimenting with it and contributing to its design. At some time, the language became known as APL, for ‘A Programming Language’. In 1962, Iverson popularized it in a book under the same title (now freely available online).

APL was created as a tool for thought and exposition, its relation to actually programming a computer being only virtual. The successful use of the language for communicating mathematical and computational ideas created a critical mass of interest that eventually lead to implementing it. Starting from 1963, a series of increasingly more complete implementations appeared.

The fact that the design of APL evolved through heavy experimentation, which was being taking place long before using it on a computer, helped keeping the language practical while semantically at a very high-level. Adhering to these goals sometimes required significant changes to the language, hardly possible had an implementation been available and used at an early stage of design. Thus APL had the chance to reach relative maturity already during its paper phase. Still, it did evolve in the later years as well.

APL is one of the earliest examples of an interpretive and interactive computing environment, and these features greatly contributed to it being appreciated by its users and to its continuous success.

An important trait of the language is its expression orientation: APL's model of computation is strongly based on evaluating expressions to produce values, as opposed to executing commands for side effects. There are assignments and gotos in APL, but an arbitrary program tends to contain much more expressions than in a traditional imperative language.

The usual statements for sequence control, typical of imperative, statement-based computation are excluded from APL for their supposed complicating the language without providing much utility. Indeed, many instances of iteration are obviated by the presence of bulk (whole-array) operations. The same holds for recursion, although the language admits recursive calls. Binary-valued evaluation and making choices computationally, within an expression, often can replace conditional execution of statements. In addition, the only form of jump statement present in the language is general enough to provide multi-way conditional branches, including returning from a function.

Expression-oriented programming is strongly encouraged by treating collections of data – even if these are solely arrays – as wholes which can be passed as arguments to suitable operations and obtained as results from them. The abundance of operations ensures a multitude of combination possibilities for constructing expressions.

With the years passing, APL's expression style evolved into an even more definite orientation towards functional programming. Functions, initially only second-class objects in the language, gradually became fully fledged values. Some modern implementations even support closures.

One thing immediately observable about APL is that it uses a special character set to depict operations. Here are some non-ASCII characters of the APL alphabet (Unicode support is needed to see them in the browser):

               ⋄ ⎕ ⍞ ⌹   ∆ ∇ ⍋ ⍒ ⍫
               × ÷ ★ ⌈ ⌊   ≤ ≥ ≠ ≢ ≡   ∨ ∧
               ← → ↓ ↑   ⊢ ⊣ ⊥ ⊤   ⊂ ⊃ ∪ ∩
               ∘ ○ ⍟ ⍤ ⍥ ⊖ ⌽ ⍉
               ⍺ ⍵ ⍴ ⍳ ∊

In a sense, even the letters of the latin alphabet are used in APL somewhat unusually. Traditionally they are printed or displayed on a screen in italics, in conformance with the way variable names are typeset in mathematical texts, and also to distinguish some letters from similarly looking other characters, e.g. L from and T from .

There are great many operations in APL. Most characters represent both a monadic and a dyadic function – this is a systematically followed design principle. Which one is in use in a particular context is determined by simple syntax rules.

APL expressions evaluate uniformly in a right-to-left direction, so there is no need for precedence or associativity rules to disambiguate the order of evaluation. Actually, the rule being postulated is that ‘the right argument of any function is the value of the entire expression following it’. This also implies that reading an expression left-to-right reveals its hierarchical structure, starting from the major operation – the one that produces the final value – and proceeding towards finer sub-expressions. Parentheses can still be used for explicit control when needed. For example, (a-bc-d+e reads: ‘the product of a-b and the expression that happens to be the difference of c and d+e’, or (a-b)×(c-(d+e)) in a fully parenthesized form.

Besides functions which operate on data and produce data, there are the so called operators. The latter take functions or data as arguments and produce functions. Unlike functions, there are only several predefined operators in most implementations of APL, and there is no possibility to define new ones. The language J, APL's most direct successor, removes this limitation, and so do some modern implementations of APL.

Syntactically, operators behave differently from functions: in any expression, the former execute before the latter, and monadic operators take their arguments from their left. For example, the expression +/m+.×v sums the elements of the product of a matrix m and a vector v. The . (dot) operator takes the functions + and × as arguments and produces a function that computes the product. The resulting vector is acted upon by the function +/ (which can be called summation), obtained by applying the operator / (reduction) on the function +.

It should be noted that this recognition of operators as a special class of functions is not shared (indeed, considered unnecessary) outside the family of APL-like languages. Historically, operators were invented and introduced one by one in APL, and at some point it was decided that they form a sufficiently important, distinct family of program objects to merit introducig special rules for them in the language. Perhaps because APL was not designed as a functional language per se, no attempt was made, nor was it desired, to unify the treatment of ordinary functions and operators.

A more usual terminology for operators used elsewhere is higher-order functions, and in a language that can work with such functions – typically functional languages but also increasingly many others – they can be created as ‘ordinary functions’ and are not considered special in any way, syntactically or otherwise.

Primitive data is called scalars in APL, and is either numbers or characters. Instead of Boolean datatype, APL makes use of the numbers 0 and 1, for ‘false’ and ‘true’ (this is a technique well known now from C-like and other languages, but it did originate in APL). Arrays of 0s and 1s are especially useful.

All structured data is arrays. In fact, even scalars are considered arrays of zero dimensions. One-dimensional arrays are called vectors or lists, two-dimensional ones – matrices or tables, and arrays of higher dimensions are multiple tables.

APL is extraordinarily efficacious in array manipulation due to two reasons. One is the richness of functions readily available in the language – some of them specifically designed for arrays, others of general utility. More functions can be obtained on-the-fly by use of operators, or by function definition. The former method gives APL a distinctive applicative flavour, akin to functional programming.

The array processing functions of APL allow creation, reorganization, searching, extraction and replacement of arbitrary sub-structures, merging, derivation of related structures (such as consisting of dimensions, indices and binary values), and other operations on arrays – all dynamic and very versatile.

It should be taken into account that APL's functions and operators are heavily loaded with meaning, mainly through generalization. The designers of the language applied much thinking to ensure that. Among the many examples, the factorial function is actually implemented as the more general gamma-function; the ‘matrix divide’ function is also generalized to implement the least-square method, so that even over-specified linear equation systems can be solved. An impressive combinatorial generalization is presented by the ‘transpose’ function, one particular case of the application of which can be seen in the Examples section below.

The other source of APL's array processing power is the pervasive way functions are used with respect to arrays. Any function defined on scalars automatically extends its action to arrays when given such argument(s). For example, x+y would mean adding two numbers if x and y happen to be numbers, while if, say, x is a number and y is an array, the same expression means adding x to each element of y. And if x is a vector and y is a matrix, then x is being added to each row (or column) of y etc. Where necessary, function application can be modified ‘rank-wise’, i.e. specifying which axes or cells in an array are to be operated on.

Because whatever dimensions an array has, ultimately it may only consist of scalars, and in this sense it is homogeneous both in its structure and in the type of its elements, a provision for building heterogeneous data structures was introduced in APL in the form of boxing. Any data item, i.e., any array, can be ‘enclosed into a box’, whereupon it effectively becomes a scalar. The elements of such an object cannot be examined or otherwise operated, unless that object is unclosed and therefore becomes a non-scalar again. Being a box and thus a scalar, however, makes it possible an array to be included – effectively nested – in other arrays. Thus, with proper boxing, arbitrary content can be put into a single array.

Boxing is also helpful for modelling multiple arguments to functions. APL functions, including user-defined ones, are restricted to being niladic, monadic, or dyadic. Therefore, whenever more than two arguments are needed, one has to resort to packing them into an array, including boxing as necessary.

As for user-defined functions, they are also uncommon in another way. Unlike most other currently used languages, but like Logo and the early implementations of Lisp, all non-local variables have dynamic scope, i.e. are resolved in the calling context rather than the textual one.

Examples

Each of the first several examples presents a single expression, which can readily be used in an unconditional direct definition of a function. The name , or both the names and are used for the parameters of monadic and dyadic expressions, respectively. While names can be chosen arbitrarily when the expressions are self-contained, the use of and is mandatory if an expression is indeed the body of a direct function definition.

Shuffling a vector – breaking ⍵ down into ⍺ pieces from which
⍝ another vector is built by merging.  E.g. if ⍵ is 'abcdefghij'
⍝ and ⍺ is 3, the pieces are 'abcd', 'efg', and 'hij', and the
⍝ result is 'aehbficgjd'

⍵[⍋⍋(⍴⍵)⍴⍳⍺]

First, ⍳⍺ gives an index list of length , which for ⍺=3 is 0 1 2. Then , with left argument ⍴⍵, repeats the contents of that list as needed to form a list the same length as . If is of length 10, then the result is 0 1 2 0 1 2 0 1 2 0. Next, the two applications of produce the grading vector of the result so far, and then the grading vector of the grading vector. For the above value of , these would be 0 3 6 9 1 4 7 2 5 8 and 0 4 7 1 5 8 2 6 9 3, respectively. Finally, by means of the subscript operator [], the elements of are extracted in the necessary order to build the shuffled vector.

The main diagonal of a square matrix ⍵, and more generally – of a hypercube ⍵, respectively

1 1⍉⍵
((⍴⍴⍵)⍴1)⍉⍵

As , as a monad, gives the vector of dimensions of its argument, ⍴⍴ is the number of those dimensions. Then the dyadic produces a vector of as many 1s to pass as a left argument to . In general, the latter function transposes the axes of its multi-dimension-array right argument according to a permutation specified by the left argument. Here, a particular case applies: repeating values in the left argument select a diagonal along those axes – and we have ensured that this is actually all axes.

A square matrix of order ⍵ that has 1s on and above its main diagonal and 0s elsewhere

(⍳⍵)∘.≤⍳⍵

The key operation here is the ∘. (outer product) operator, which produces a table of a function – in this case the comparison – for a given pair of vector arguments. Both arguments are the same increasing sequence ⍳⍵, hence the result.

A function that finds the list of Fibonacci numbers,
⍝ up to specified length (argument k)ffib k
[1]   f ← ,1
[2]   → (k=⍴f)/0
[3]   ff,+/¯2↑f
[4]   → 2
    ∇

Unlike the above, each of which was a single expression, this is an example of a complete function definition. Its first line defines f to be the result of the function fib, which happens to be monadic with an argument called k, defining how many items we want in f. The main computation is on line 3: f's two trailing numbers are extracted into a two-element vector (¯2↑f) and added together (+/), giving the new item to be appended (,) to f's contents. The so obtained vector is assigned () as a new value to f. Line 4 is a jump to line 2, where it is checked whether f already contains enough items, and if so, a jump to 0 is performed, which, as 0 is not a valid line number, is equivalent to return from the function. If the length of f is less than k, the selection operation (k=⍴f)/0 gives an empty vector, a jump to which is by definition a no-jump, so the execution continues in normal order, at line 3. Initially, f is given a vector of one element, 1. Note that even for that f the expression ¯2↑f has a correct value.

A so-called ‘direct’, recursive definition of a Fibonacci function

fbr: f,+/¯2↑ffbr ⍵-1 : ⍵=1 : 1

Here, is the obligatory argument name for a direct definition, and f is a local variable. The part after the second : is a condition which determines whether the value to be returned shall be produced by the expression on the right, or the one on the left. The latter expression contains a recursive call of the function fbr to itself, the result of which is handled similarly to the way the above non-recursive version of the function does.

Application, Goals, and Influence

As a programming language, APL is popular in finance, insurance, mathematical and science experimenting and sumulations, and engineering, and is considered a highly effective rapid prototyping tool in even more areas. Also, being array-oriented, APL has great potential for exploiting SIMD and multi-core computer architectures.

Several companies have been closely related to the commercial use and development of APL. Among them, IBM has a special place. The early development of APL took place at IBM, and this is also where the first implementation of the language was made. As a result of an experiment called SCAMP, a desktop calculator – an interactive APL programming device, was created in 1973, followed in 1975 by the first IBM personal computer, IBM 5100 – a system intended for the educational market which had APL optionally installed. (Another, much smaller company, also succeeded in creating their own personal computer, MCM/70, with a built-in APL system – even a bit earlier than IBM!)

However, APL's principal author was convinced – something he expressed in numerous publications – that APL's most important use was ‘as an executable notation for the teaching of a wide range of subjects’, mathematics in particular. According to him, APL was to develop into a streamlined mathematical notation – inambiguous, free of singularities, and with the executability and universality characteristic of a programming language.

In the late 1980s, Iverson's evolution of ideas about APL required changing the language so substantially that eventually he created a new one, J. Other array processing languages were also heavily influenced by APL, or even directly descend from it. A very successful language of this kind is K.

Iverson experimented in teaching mathematical disciplines, such as algebra and calculus, using APL (and later J) in place of the usual mathematical notation. He used APL and J in writing a series of books in the said disciplines.

The work of K. Iverson on APL, in particular – showing a style of programming that emphasizes the processing of whole arrays rather than individual items, and that makes use of operators to create functions from given functions – was part of the motivation for J. Backus to create FP. The applicative style, promoted by FP, was in turn influential in shaping modern functional programming. Thus today's functional programming originates, in part, from APL.

Links of Relevance

A programming language: a book describing an early version of APL; available online as a scanned copy and in Web format

The APL (and J) archives at the University of Waterloo
The draft standard for APL (very close to the actual ISO 8485 standard)

An F.A.Q. list about APL

Vector (or this way): the web page of the Journal of the British APL Association. Provides links to APL (and its descendants) resources

A page celebrating Kenneth Iverson's life: his works, writings of others about him and APL, witty quotations, and other texts
Papers, manuals, and other items written by K. Iverson
“Notation as a tool of thought”: K.E. Iverson’s 1979 Turing Award Lecture

The APL Wiki page: some examples, resources

The FinnAPL Idiom Library: a collection of idiomatic phrases solving a number of problems

The APL Idiom List: an older collection of idiomatic solutions (Perlis & Rugaber)

Mastering Dyalog APL: a book on APL programming, available both in print and online (PDF)

APL interpreters that are either free or have free trial versions:
Sharp APL for Linux, and an older version of the same, for MS-DOS
APL-PLUS and APLSE: APL versions for MS-DOS
I-APL: another APL for MS-DOS, with sources
Dyalog APL
Documentation
TryAPL: on-line interpreter and tutorial
APL2: IBM's dialect of APL (for mainframes)
Documentation
Idiomatic phrases
APL2 for PCs
APLX: an advanced, modern implementation of APL with enhancements
NARS2000: an experimental APL interpreter
openAPL: an APL dialect implemented for Linux, a branch of the APL\11 dialect (now perhaps too old)
A+ (or here): a ‘reduced instruction set APL’
The first IBM personal computer, IBM 5100 – it had APL optionally installed:
at the IBM history page
at the Retrocomputing Museum
at the Obsolete Technology Website
MCM/70: an even earlier micro- and portable computer with a built-in APL interpreter:
at old-computers.com
at the York University Computer Museum (YUCoM)
The Making of the MCM/70 Microcomputer, in: IEEE Annals of the History of Computing
at Wikipedia

boykobbatgmaildotcom