www.vector.org.uk >
back issues >
contents of Vector 16.2
Note that this article contains quite a bit of APL code - this is in APL2741 font, downloadable from this site (32K). There is a new problem in showing the {match} symbol in IE5 (it is treated as an optional hyphen), so it has now been duplicated in the font at position ch(166) which will paste into APL*PLUS as the split-stile character. If you already have the font, please check the build date (double-click the font in your fonts folder) and re-install it if you don't have the October 29th 1999 version.
by Dan Baronet (danb@dsuper.net)
Following Solitons announcement to unleash their APL into the Linux community I decided to review the differences between SHARP APL and APL2 style APLs (IBMs APL2, Dyalog, APL+Win). I have divided the report into several articles, each with a different topic.
This article is the first of the series. It should be read before any of the others.
Not having a current version of IBMs APL2 on hand I have
been making my observations based on Dyalogs APL using
ml=2,
which, like APL+Win, follows APL2 closely.
When reading this text keep in mind the date it was written (September 1999) as languages change and may render this information incorrect in the future.
In the text italicized words have a special meaning and often precede their definition.
SAPL refers to SHARP APL, including SAM which is SAPL under MVS and SAX which is SAPL under Unix. SAX is the one also running under Linux and compared to APL2 here.
Variables and workspace names are enclosed in quotes. Functions and files are enclosed in <angle brackets>.
The term atom refers to a numeric or character scalar only. The term item refers to any scalar.
Whenever possible I will show examples in SAPL and APL2 side by side.
SHARP APL (SAPL) used to be a mainframe product only until a PC version appeared in 1984 (release V17 of SAM and rel V20 later on). It remained pretty much so as the PC version never took off. The PC version ran under DOS and lacked many features. Because it was emulating the S/370 it was also very slow.
SAPL really is a product as opposed to a language. There are various components including a batch scheduler, a file system, many shared variable processors, sorting utilities, etc. More importantly, SAPL tasks may spawn and control other APL tasks with system functions, something no other APL has ever achieved. Very large secure systems can be (and have been) written in SAPL.
By contrast, in IBMs APL21, everything but the language is external and only available through auxiliary processors (APs). There are no quad functions, for example, to perform file operations.
There are pros and cons for using each APL and the purpose of this article is not to take sides but rather to show the differences between them as objectively as possible.
SAX came to life in the early 90s and is a more flexible version of SAM. It is based on the Dictionary of APL by Ken Iverson. It extends SAM V21. It more closely resembles J. (Think of J on APL char set.) The Linux version is the same as the Unix version.
At some point there was a shift in philosophy using the first
versus the last axis in function operations (ex: /
vs.
) and some newer functions were defined in
terms of the latter. APL2 has remained pretty much a last
axis favoured language.
In SAPL the term enclosed array is used. In APL2 the term used is nested array. They are, practically, the same thing. The term boxed array (SAX) is also sometimes seen but wont be used here.
Lets assume we have the following variables on hand:
a'text' b1 2 3 c2 3a d2 4 333
The simplest way to create an enclosed item is to use the expression
| SAX APL2 | APL2 |
|---|---|
x<anyvalue | xanyvalue
|
In SAPL there is no maximum level
(depth) of enclosure. Thus <<<a
is a enclosed 3 times. In IBMs
APL2 there is a limit.
Items must be opened before applying a function to them.
If x<2 3 4 then
+/>x +/x
will result in the sum of the values in x.
To create a list (vector) of enclosed items we can use the
usual catenate function (,
):
x(<a),(<b),<c x(a),(b),c
This will ALWAYS work in all interpreters I know. But there is an easier (incompatible) way to do this:
xabc x a b c
Which brings us to the way things are presented to the interpreter.
APL2 uses what is known as strand
notation. Using this notation, arrays are created by putting items
together side by side, without using catenate (,)
as in the example above. Sometimes it is handier than using ,.
SAX does not support that notation and requires the use of functions
, to catenate items together or to link them if they are to be enclosed.
Link is a specific SAPL function to enclose and catenate with a twist. To understand its use lets look at the monadic case first:
This is another function specific to SAPL. The formal definition is: enclose the argument IF it does NOT contain already enclosed item(s). Sort of a conditional enclose. In fact conditional enclose is its real name. See its usage2:
xvar (1<|xvar)/'xvar'
An application of this is to determine whether we are dealing with an enclosed array or not:
xx 1<|x
will return 1 if x is enclosed. There is no depth function in SAPL.
ab
will enclose a and catenate it to the enclosure of
b if b does NOT contain enclosed elements.
Formally,
ab
is the same as
(<a),b
Why not use (<a),<b
? The reason is to avoid enclosing
a list repeatedly. Imagine what would happen if it were to always
enclose the right argument in the expression
abc.
This would result in (<a)
,<(<b),<c
, a two-element list. This is not what we
want. A consequence of this is that one must explicitly code the
enclosure of the last item if the last value MUST be enclosed,
as in xab<m
(with m2
3<a), to get
a three-element list.
On the other hand, if we want to, say, catenate
<a
before each row of m then am
will
do whereas (a),m
is
required in APL2.
Both APLs support arrays containing a mixture of items of different data types, namely characters, numbers and enclosures although they must be explicitly catenated in SAX:
x1,'s' x1 's' x1,'s',<'sa' x1 's' 'sa' x1,'s','sa'2 3 x1 's' 'sa'(2 3)
Entire arrays can be disclosed in one fell swoop with only space and maximum rank (127) restrictions:
2 3 >1'dsa' 2 3 1'dsa'
In Dyalog there is a same rank restriction3. Not in SAX:
4 2 4 4 >abcd |
(RANK ERROR in Dyalog and APL+PLUS II) |
Disclosing an array results in another array of the shape of the array disclosed, followed by the largest of the shapes of ALL items disclosed with proper fill elements to fill where necessary.
A major difference between SAPL and APL2 is in the handling of atoms (simple scalars) upon enclosing them. In SAPL enclosing ANYTHING adds a level of enclosure. Not so in APL2 where an atom can NEVER be enclosed. Thus:
~2<2 22
This has several implications as we shall see in a later article.
The disclosure of an atom is permissible in both APLs. Thus
2>2 22
SAPL offers a few operators to work with (enclosed) arrays. I will discuss only the basics in this article. The next article will cover the subject in more depth (no pun intended).
)Although Under is the official name under SAX, people often refer to it as With. APL2 uses the term Each.
With /
this is the most used operator in
ALL APLs. It is probably best explained starting with an example:
>x x
Here we wish to return the shape of each item by first disclosing (each) cell of x, getting its shape and re-enclosing it, ending with a result of the same shape as the original argument.
In SAPL
is dyadic, allowing for a different right function. The people
at APL2 probably felt that since disclose/enclose is used
most of the time it was better to make
monadic and include these functions implicitly
whereas at I.P.Sharp (where SAPL came from) people tried to be
more general.
Some interesting combinations can
be made with 2 functions and
although
99% of the time
disclose (>
) is used.
An example is multiplication:
AB is *(A)+(B) or A+B
The real APL2 definition is: for each cell:
The real SAPL definition is: for each cell:
(usually<)
Or, given f
g
y, for each cell: g-1 f g y[j].
This, of course, implies that someone
in the interpreter department goes over all the suitable right
hand argument functions and determines an inverse for each one
of them. And it was done. For example, <
and >
are inverses of each other.
is its own inverse.
g y
is, for each corresponding cell:
g-1 (g x[j]) f (g y[j]).
Where x is the left argument.
Examples:
p > q p
q (reshape
each)
t1,>t2 t1, t2 (catenate each)
In APL2, the use of the each operator is assumed for scalar functions (like + ) and derived functions, enclosed or not. There is no need to specify it. Ex:
x+>y x+y
Moreover, the function is applied recursively so long as the lengths are respected at each (nested) level. This is not possible in SAX.
The reason is that since disclose is implied and that an atom can NEVER be enclosed in APL2 then the each specification can be omitted. Structural functions like take must use each to remove ambiguities.
This is also why
+/x and
+/x
mean two different things
in APL2. In SAX those would be coded as +>/x
and +/>x
respectively.
)This operator is similar to with except that the result of each cell is not modified by the inverse of g.
and
are called composition
operators. The only difference between them is in the absence
of inverse for the right argument function of
.
For example,
using f
> y
is the same as doing
>f> y f y
This may seem trivial but I will show in a subsequent article, along with another operator, the implications of using this operator.
SAPL supports the use of alpha ()
and omega () as APL identifiers for variables, functions and labels.
These were introduced when the /
direct definition notation was popular (late seventies).
The wisdom of their usage in code is debatable but they are available.
Also SAPL literature often refers to the left argument as alpha
and the right argument as omega. Something to keep in mind.
These are not available in SAX yet.
These are not APL2 but are worth a mention anyway. They do not exist in SAX. In a subsequent article I will show how to emulate them in a control version system that Soliton provides.
SAPL does not allow you to define your own operators.
Similar to Dyalog APL. Even the event numbers are almost the same. A notable difference: the ability to trap value errors in line and resume after solving the error. This allows you to easily do demand paging of objects.
In SAPL those are more like APL+Win.
System functions dont start with an F (
read
, not
fread
). All file operations
return a result, that is val
replace tc returns
0 00
. This allows someone to use them with operators.
SAX allows the usage of a character
left argument to the format primitive
. This is the same as IBMs APL2 (not
found in Dyalog or APL+Win).
It is possible, in both APLs, to assign with disclose several values to several variables by using quotes around the variables5:
'a b'2 5'cxz' (a b)(2 5)'czx'
There is a peculiarity using this technique where the number of variables is 1:
'a b c'11 21 2 3 ('c' is 1 2 3)
'b c'1 21 2 3 (again, 'c' is 1 2 3)
'c'1 2 3 (now 'c' is <1 2 3, NOT 1 2 3)
This behaviour is found on ALL APLs (also in J!).
Personally, I think this is inconsistent. If there are no quotes (or parentheses) it should be a direct assignment. If there are some it should ALWAYS remove one level of nesting before assigning the value(s).
From is an alternative to bracket indexing. The beauty with from is that since it IS a function it does not suffer bracket syntax problems and can be used with operators.
From selects elements along the first dimension. Used with list arguments it selects individual items:
n{list nlist
Pick
(dyadic
in APL2) and First
(monadic
) are not available under SAX. You can still
use > with brackets [x] or use from ({):
x>atom{list xatomlist
Note that from is
io
independent. It uses an offset instead of an origin dependent
position (index). from also allows you to select items
from the end of the array by supplying negative offsets. Ex:
't'=3{a 't'=(3+io)a
't'^.=0 3{a 't'^.=a[1 4] (in io 1)
'x'=2{a 'x'=a[io+(a)+2]
In APL2 prototypes are used to fill
holes created by \
or
. Ex: 2
202 25
. SAPL has no prototype. If x
is an item, the expression 0\x
always returns either 0 for a number,
blank for a character or <0
for an enclosed object.
IBMs APL2 allows you to reduce along an axis in sections of length N (N f/ x). Not in SAPL.
Those are set using
stop
and trace
system functions as in Dyalog APL. IBMs
APL2 uses t
and s
special name prefixes to do the same.
In SAX these functions work on the
leading axis of an array without having to specify them all. Ex
(?=
m):
2m (2,1m)m 2m ((1m)2)m
IBMs APL2 allows you to use take with one axis as in
3m 3[1]m
When the argument has a rank higher than 1 then indices should be enclosed:
(<1 2){d (1 2) d
(1 20 1){d (1 2)(0 1)d (io 0)
But you can pick an entire row (or first dimension elements) by supplying the offset only:
2 3 1 3 { 4 3 12
This operator merely swaps the arguments
to a function. Dyalog uses for that. For ex:
2=7-9
Here is a list of features not found in any other APL.
This function returns the index of
the first occurrence using epsilon underbar (
)as
primary function:
2 3(4 520)2 2 8 9 13 14 (io 1)
is a constant whose value is <0
. This is the constant used for overtake
and \
with enclosed or heterogeneous arrays.
This one is not unique to SAX (Dyalogs
equivalent is ) but it handles higher rank arrays:
5 2 9 5 2 (m[73;] ) m3 4 'johnmarypaul'
=)
, nubsieve (monadic
)=x
is the equivalent of (x).=x
for vectors
returns a boolean indicating where each element is first encountered.
This is the equivalent of ((vv)=v)
for vectors. Works on matrices too such
that
1 0 1 0 1 0 2 m
It is possible to send all input/output
to a file using out 0,tie
.
Packages are unique to SAPL and are
very useful. A series of system functions can be used with them,
all of which start with p
as in pack
, pdef
, etc. For example, to define variable x
with objects (variables, functions) a and <f>
(for example to be stored on file) you would do
xpack 'a f'
Think of them as static namespaces (found only in Dyalog). You cannot enter a package and run something from within it. For example, if you wish to use its contents in a local environment you must first localize the names. For example, this function <execin> will execute an expression using a packages contents:
rexp execin pack;f
[1]fx>('f',,';',pnames pack)'pdef pack r',exp
These two functions are probably the simplest ever conceived yet very useful.
Stop:
dl 5 0 0dl 5 x2y5 y5 x2
Pass:
x1 2 3 x1 2 3
This last function is more useful than it looks. For example, if space is important and you do not want the interpreter to keep a copy of the argument to a function you could do
myfn (ex 'x')x
This effectively erases the variable AFTER passing it as an argument to <myfn>. The interpreter is then able to free up the memory space, should the need arise later on (for example after you reassign the argument within <myfn>). I dont know of any other general way to do this with any other interpreter.
These are a leftover from the 60s. If you think you know what they are you probably werent there. They are kept for compatibility reasons with SAM (many are no-ops) and will not be explained here.
This one is not unique to SAPL (most APLs handle the vector case) but it accepts higher rank arrays:
12 7 1 7 12 5 ~ 6 'john' ,m~m[2 3;]
This is an interesting monadic function (in terms of raison dtre). Its formal definition is
>
In other words, working from the first dimension: catenate on the first dimension all items.
My guess is that this came from a
requirement to create in SAPL a function reminiscent of APL2s
monadic
which puts everything in ravel order regardless of structural
depth6. Before raze programmers would often need to get
text (or numbers) from enclosed lists together, sort of
>,>/
but SAM wouldnt allow it resulting in expressions like ,
x
(plus fi
if numeric) being used resulting in high
CPU costs. Hence raze was created. Plus it can be useful.
svs
returns the status of a variable
sc
is used to wait on ANY shared variable event. It can also be assigned
a maximum wait time.
svn
is used to uniquely identify your task when multi-tasking.
SAX commands are similar to other APLs.
)copy
allows the copying of system variables.
)load
and )clear
allow you to specify initial
wa.
Ex:
)clear 200000000
will give you a workspace of 200M if you
have the room!
Various workspace elements (name,
stack) can be found using ws
.
fd
can be used to manipulate function representations (similar to
def
, vr
in APL+Win).
Of course ISO standard functions
like cr
and fx
also exist.
ps
controls the formatting of enclosed arrays. It is a four-elements
integer list of
1=left,
0=centre, 1=right)
1=up,
0=centre, 1=down)
The default 1
1 0 1 fits most
cases.
sp
is used to store values. It stays the same between
)loads
. Probably one of the most valuable system
variables ever created.
10{av
is the character used as line delimiter. Not
13{av.
One should exercise caution with this.
)This function restructures any structure into a matrix, something like
(2(t),1 1)t
Table turns a scalar into a 1 by 1, a vector into a 1 column table, anything else into a table.
This is possible in SAX and will be the subject of another article.
SAPL and APL2 are quite different in many respects but each (!) has its own merits. For anyone wishing to delve into the APL/Linux world there is, right now, little choice but to examine SAPL. Personally I am comfortable with both. I found SAPL to be fast, reliable and, with the tools Soliton is providing, a serious product.
The next article will deal with special SAPL operators (hoof, rank, cut, numeric with, }). Another one will deal with multi-task operations. If time permits, another one will talk about intrinsic functions and one of Solitons products, logos.
Please direct questions/remarks to danb@dsuper.net.
Dan Baronet