Throughout this lesson there are snippets of code as examples. You are encouraged to edit and experiment with these – it will greatly improve your understanding.
All data in APL resides in arrays. An array is a rectangular collection of numbers, characters and arrays, arranged along zero or more axes. Numbers and characters are 0 dimensional arrays, and are referred to as scalars. Characters are in single quotes.
Creating a 1-dimensional array is very simple: just write the elements next to each other, separated by spaces. This syntax works for any data that you want in the array: numbers, characters, other arrays (etc.)
A string is just a character vector, which may be written with single quotes around the entire string.
Parentheses are used to group array items.
2 3 5 7 11
'A' 'P' 'L'
'APL'
(1 4 2) (4 3) (99 10)
Numbers are very straight forward: a number is a number. It doesn't matter if it is an integer or not, nor if it is real or complex. Negative numbers are denoted by a 'high minus': ¯
. You can also use scientific notation with e
(or E
), so a million is 1E6
The items of an array can be of different types.
'Hello' 100 (1 'b' 2.5)
¯2 3e2 2e¯1
An array has a rank and a depth.
The depth is the level of nesting. For example an array of simple (i.e. non-nested) scalars has depth 1, an array containing only depth 1 arrays has depth 2 and a simple scalar (e.g a number or character) has depth 0. However, for some arrays it's not so easy. An array may contain both vectors and scalars. In cases like this, the depth is reported as negative.
You can find the depth of an array with the function ≡
.
≡ 1
≡ 'APL'
≡ ((1 2) (3 7)) ((99 12) (1 2 3) 'Hey')
≡ 1 'Hello' 33 'World'
The concept of rank is very important in APL, and isn't present in many other languages. It refers to the number of dimensions in the array. So far, we've only seen rank 0 arrays (scalars), and rank 1 arrays (vectors). You can, however, have arrays of other ranks. A rank 2 array, for example, is often called a matrix or a table.
Arrays are always rectangular; each row of a matrix must have the same number of columns. Each layer of a 3D block must have the same number of rows and columns. As our screens are only two-dimensional, higher rank arrays are printed layer-by-layer.
Creating arrays of ranks greater than 1 is only slightly harder than creating vectors. To do so we can use the function ⍴
(Greek letter "rho" for reshape). It takes a vector of dimension lengths as a left argument and any array as a right argument. It returns a new array with the specified dimensions, filled with the data of the right argument. If there is too much data, the tail just doesn't get used. If there is too little, it gets recycled from the beginning.
2 2⍴1 2 3 4
2 3 2⍴1 0 0 1 1 1 0 1 1 0 0 1
3⍴5 4 3 2 1
3 4⍴'abc'
It doesn't matter what the rank of the right argument of ⍴
is:
4 5⍴(3 4⍴'ABC')
Matrices don't have to contain only scalars. Like vectors (and all other arrays), they can be nested.
3 2⍴(1 2)(3 4)(5 6)
2 2⍴(3 2⍴'x')(2 1⍴(2 2⍴0)(2 2⍴1))
Depth is general to arrays of any rank. The depth of an array isn't just the nesting level of vectors, as shown previously, but of any array. So an array of depth-1 matrices has depth 2, and a matrix of numeric vectors also has depth 2. A matrix of scalars will have depth 1, like any array of scalars.
≡ (5 3⍴1 4 3 7)
≡ (2 2⍴0) (3 1 4⍴11)
≡ (7 7 7⍴(2 2⍴0) 'abc')
Of course, all arrays of uneven depths are dealt with in the same way as vectors.
≡ (2 2⍴('APL' 360) 1 2)
The depth of the previous example is ¯3
because the 'A'
in 'APL'
is at a depth of 3 and the depth of the array is uneven.
APL also has empty arrays: ⍬
is the empty numeric array and ''
is the empty character array.
The function ⍴
also has a meaning monadically, when applied to only one argument. It returns the shape of its argument - the lengths of its dimensions.
⍴ 'abcd'
⍴ (2 2 ⍴ 1 2 3 4)
⍴ ⍬
⍴ ''
There is a distinction between single row matrices and vectors, even if they look the same when printed.
1 3⍴1 2 3
⍴ (1 3⍴1 2 3)
⍴ 1 2 3
Note the identity: X ≡ ⍴ (X ⍴ A)
. After reshaping an array with X
, it's shape will always be X
.
The length of the shape of an array is equal to its rank. Therefore, we can find the rank of an array with ⍴⍴
- The shape of the shape.
Since a scalar is rank 0 (i.e it has no dimensions) the shape of a scalar has length 0 and is an empty vector: ⍬
⍴⍴ 'abc'
⍴⍴ (3 4 2 5⍴42)
⍴⍴ 'q'
⍴ 'b'
You can use ⍴
to convert between a rank-0 scalar and a rank-1 vector. A scalar has shape ⍬
and a length 1 vector has shape 1
.
⍴⍴ (1⍴10)
⍴⍴ (⍬⍴(1⍴10))