APL in R
Jan de Leeuw
Version 009, March 07, 2016
APL was introduced by Iverson (1962). It is an array language, with many functions to manipulate multidimensional arrays. R also has multidimensional arrays, but not as many functions to work with them.
In R there are no scalars, there are vectors of length one. For a vector
x in R we have
dim(x) equal to
length(x) > 0. For an array, including a matrix, we have
length(dim(x)) > 0. APL is an array language, which means everything is an array. For each array both the shape ⍴A and the rank ⍴⍴A are defined. Scalars are arrays with shape equal to one, vectors are arrays with rank equal to one.
If you want to evaluate APL expressions using a traditional APL virtual keyboard, we recommend the nice webpage at ngn.github.io/apl/web/index.html. EliStudio at fastarray.appspot.com/default.html is essentially an APL interpreter running in a Qt GUI, using ascii symbols and symbol-pairs to replace traditional APL symbols (Chen and Ching (2013)). Eli does not have nested arrays. It does have ecc, which compiles eli to C.
In 1994 one of us coded most APL array operations in
XLISP-STAT. The code is still available at gifi.stat.ucla.edu/apl.
There are some important differences between the R and Lisp versions, because Lisp and APL both have C’s row-major ordering, while R (like
Fortran’s column-major ordering in the array layout. Our R version of APL uses column-major ordering. By slightly changing the two basic building blocks of our code, the
aplEncode() functions, it would be easy to choose between row-major and column-major layouts. But this would make it more complicated to use the code with the rest of R.
Because of layout, the two arrays 3 3 3⍴⍳27 and
array(1:27,rep(3,3)) are different. But what is really helpful in linking the two environments is that ,3 3 3⍴⍳27 and
as.vector(array(1:27,rep(3,3)), which both ravel the array to a vector, give the same result, the vector ⍳27 or
1:27. This is, of course, because ravelling an array is the inverse of reshaping a vector.
Most of the functions in R are written with arrays of numbers in mind. Most of them will work for array with elements of type logical, and quite a few of them will also work for arrays of type character. We have to keep in mind, however, that APL and R treat character arrays quite differently. In R we have
length("aa") equal to 1, because
"aa" is a vector with as its single element the string
"aa". R has no primitive character type, characters are just strings which happen to have only one character in them. In APL strings themselves are vectors of characters, and ⍴aa is 2. In R we can say
a<-array("aa",c(2,2,2)), but in APL this gives a domain error. In APL we can say 2 2 2⍴“aa”, which gives the same result as 2 2 2⍴“a” or 2 2 2⍴‘a’.
In this version of the code we have not implemented the nested arrays of
APL-2. Nesting gives every array
A not just a shape ⍴A and a rank ⍴⍴A, but also a depth. The depth of an array of numbers or characters is one, the depth of a nested array is the maximum depth of its elements.
There are many dialects of APL, and quite a few languages derived from APL, such as
J. As a standard for
APL-I we use Helzer (1989).