Copyright (C) 1992, 1997 by Thomas Glen Smith. All rights reserved.
For more information regarding the CAPLIB2 software package, contact -
Thomas Glen Smith
3154 West Shady Lane
Neenah, Wisconsin 54956
Telephone (920) 836-2543
Compuserve: 76207,3343
The file cap2/bin/apl2 is an APL Interpreter, the source for which is
protected under the GNU General Public License.
This READ.ME file contains a brief description of the APL language,
and the extensions introduced with IBM's APL2. Much of the functionality
of APL and APL2 is provided in CAPLIB2. I've written a book, "CAPLIB2:
APL for Programmers in C" that goes into great detail, but I've not yet
found a publisher.
..........................................................................
Support Policy
While every effort is made to ensure the CAPLIB2 routines and
documentation are free from defects, there is no warranty. You can
contact me by mail, or at the Compuserve address indicated above. I'll
help if I can.
..........................................................................
What is CAPLIB2?
CAPLIB2 contains an interpreter that lets you program directly in APL on
a standard IBM PC or compatible, presently under either DOS or the Linux
operating system. Since it's written in C, it can be easily ported to
other operating systems.
APL was invented by Dr. Ken Iverson while he worked at Harvard. He
published a book, "A Programming Language," in 1962, and continued his
work on the language at IBM. IBM marketed an APL Interpreter,
documented in IBM publication GC26-3847-4, "APL Language," Fifth
Edition, July 1978. In 1992, I published, for sale, CAPLIB, an APL
interpreter, written in C, that was an implementation of the APL
language as documented in IBM's publication. That same year, IBM
announced APL2, a new and improved APL. I sold three copies of CAPLIB.
Only slightly daunted, I began work on CAPLIB2, an implementation of
APL2 as documented in IBM publication SH21-1061-00, "APL2 Programming:
Language Reference," First Edition, March 1992.
..........................................................................
CAPLIB2 is Free
Yup, it's (gulp) free. CAPLIB was proprietary, though I'd sell you a
copy of the source. CAPLIB2 is free software, protected under the GNU
General Public License, a complete copy of which is in file gnu.txt.
Briefly, this means you can give away or even sell copies of CAPLIB2, as
long as you conspicuously attach a copy of the GNU copyright notice and
disclaimer of warranty, supply copies of the source, and permit your
customers to give away free copies of what you sold or gave them.
You can also modify CAPLIB2 source, or add to it, so long as you clearly
indicate what you've changed or added (so the next person who uses it
won't blame me for your mistakes), and protect your changes or additions
under the GNU General Public License. In other words, your stuff must
be free, too. In fact, if it's good, I want a copy!
Reading an article by Kevin Kelly titled "New Rules for the New
Economy," in the September 1997 issue of Wired magazine finally
convinced me to make CAPLIB2 free. Though he describes the "Network
Economy," the Internet being it's principal manifestation, he's equally
describing the success or failure of computer programs. He says,
"There is no future for hermetically sealed closed systems in
the Network Economy. The more dimensions accessible to member
input and creation, the more increasing returns can animate the
network, the more the system will feed on itself and prosper.
The less it allows these, the more it will be bypassed... The
Network Economy rewards schemes that allow decentralized
creation and punishes those that don't."
Like the dinosaurs, the day of proprietary, OCO (Object Code Only, a
term originated I think by IBM) software is over. On the Internet, free
software can adapt and mutate, quickly getting better, while propriety
stuff can't, because changes only come with the next release from the
vendor. Free programs behave like entities in a biome, developing
through a process of natural selection.
I still plan on making money from CAPLIB2 by offering a service. I'll
be examining the ``mutations,'' incorporating good ones that're downward
compatible in a new version. The source for each new ``mutated'' CAPLIB2
will still be free, as it must to comply with the GNU General Public
License, but you'll pay a service charge to get a copy from me. Of
course, others may also offer such a service. It's up to me to make it
worth your while to get yours from me.
..........................................................................
APL statements are easily translated to C
With CAPLIB2 you can interactively explore problem solutions in APL.
Once you've found the best solution, if you need greater efficiency, you
can incorporate that logic in a C program through calls to routines in
the CAPLIB2 C-library. There are over seven hundred CAPLIB2
subroutines, compared to four hundred in CAPLIB. Any APL statement
involving standard APL functions and operators can be directly
translated to a single C language statement using calls to CAPLIB2
routines.
..........................................................................
Trying the APL Interpreter
To try the APL interpreter, invoke cap2/bin/apl2. The interpreter will
prompt you with "APL>". To stop the interpreter and return to a Linux
shell prompt, key ")off" and press Enter.
If you've used APL before and you're reading this for the first time,
you may think ")off" is a typographical error. It should read ")OFF"
since the APL symbol set doesn't include lower case letters. CAPLIB2
maps the upper case letters in the APL symbol set to the lower case
letters of the PC keyboard.
There are also about 27 other symbols on a typical APL keyboard that
don't show up on the standard PC keyboard, and 19 symbols that are
composites, produced by keying one symbol, pressing the backspace key,
and overtyping with a second. There's also the underscored letters A to
Z. CAPLIB2 maps all these symbols to a standard PC keyboard. There's a
function that helps you with this mapping while you're using APL. To
use it, invoke cap2/bin/apl2 while in the cap2/help subdirectory, and
when you see the prompt "APL>" enter ")copy help helpgroup". When you
see the "APL>" prompt again, try -
help 'I'
which will display the following:
I iota symbol, index generator, index of
I index generator, I5 is 1 2 3 4 5
I index of, 'abc ' I 'b c a' is 2 4 3 4 1
This is telling you that "I" represents the APL iota symbol, which
invokes two APL functions called "index generator" and "index of."
An example of "index generator" is
I5
which produces the string of numbers "1 2 3 4 5". An example of
"index of" is
'abc ' I 'b c a'
which produces the string of numbers "2 4 3 4 1" indicating the "b"
in 'b c a' is located in position 2 in 'abc ', " " (a space) is at
position 4, "c" at position 3, and so on.
Once you've done the ")copy help helpgroup" you can enter help 'x'
where x is any character on the keyboard, to get a description of
what that key represents in the APL symbol set. Just be sure you
surround the character in single quotes. Entering, for example -
help y
may get you an error message like, "59 - Operand not found where
expected during execute."
You can also use "help" to find out about specific APL functions.
Suppose you think you want to use the APL factorial function, but
you don't remember exactly how it works. You can find out by
entering -
help 'factorial'
which will display the following:
! factorial, !5 is 120
This is telling you that the exclamation point (!) invokes the
factorial function, and that !5 produces 120, which of course is
5 X 4 X 3 X 2 X 1, the standard factorial function learned in grade
school algebra.
..........................................................................
Video Display of APL Symbols
If you invoke the APL command, the PC monitor shows the normal keyboard
characters as you press them. But, in DOS only, if you invoke APLF, APL
symbols are displayed. I prefer that "M" be displayed when I press
Shift and the "m" key, and "M" maps in my mind with no trouble or
confusion to the domino APL symbol. But if you want to see the APL
domino, iota, etc., use APLF under DOS.
..........................................................................
CAPLIB2, DOS versus Linux
The only significant difference between the DOS and Linux versions of
the CAPLIB2 interpreter and routine library, is that everything under
Linux is 32 bit, whereas under DOS some things, like the sizes of
variables, are limited to a binary number that fits into 16 bits.
Integers under both DOS and Linux are 32 bits, but arrays can only be
32767 bytes long in DOS, but are limited to 4,294,967,295 bytes under
Linux.
..........................................................................
APL Tutorial
This is a brief introduction to the APL language. A detailed
explanation is in the book "CAPLIB2: APL for Programmers in C"
copyright 1997, by Thomas Glen Smith (that's me).
Most of us who claim to be programmers were introduced to the craft
with a procedure-oriented language such as BASIC, FORTRAN, PL/1, or
C. The keywords and syntax may differ from one to the next, but a
programmer uses similar logic with each of these languages to arrive
at solutions. Their operators typically deal only with one item at a
time, and one must define a loop to iteratively process arrays of
items. For example, this C program adds 5 numbers and prints the sum:
#include <stdio.h>
#include <stdlib.h>
main()
{
static double a[5] = {11.0, 22.1, 3.2, 43.5, 71.4};
double sum=0.0;
int i;
for ( i=0; i<5; i++ ) sum += a[i];
printf("sum = %5.2f",sum);
}
sum = 151.20
Contrast the above with the solution of the same problem in APL:
+ / 22.1 3.2 43.5 71.4
151.2
First, of course, you'll notice the conciseness. There are pros and
cons to this. There's the obvious advantage of a smaller source to
maintain. But in a more complicated APL program, when it comes time
to make changes a few months after it was written, it can be difficult
to understand the intent of the program simply by reading the source.
You've heard of read-only memory? Some critics of APL refer to it as
the "write-only" language.
Be that as is it may, the real advantage of APL hasn't been pointed
out yet. Namely, that its structure is carried along with data, and
is removed from the program. Suppose we wanted to change the problem
to find the sum of six numbers instead of five. In our sample C
program we would need to change the "for" statement to test for i
less than 6 instead of 5. But in APL all we change is the data:
+ / 22.1 3.2 43.5 71.4 89.5
240.7
..........................................................................
Overview of APL
APL consists of three fundamentals: arrays; functions; and operators.
Arrays are structured collections of data, either numbers or
characters. Functions accept arrays as arguments, and produce new
arrays as results. Operators accept both arrays and functions,
applying the functions in special ways, also producing new arrays
as results.
..........................................................................
APL Arrays
Arrays are the means in APL for organizing and storing data. An array
can consist of either numeric or character data, but not both in classic
APL. In IBM's APL2 and CAPLIB2, arrays can be a mixture of character
and numeric. An item can even be an array, whose items can be arrays,
and so on. Such an array is called nested.
Arrays have rank indicating the number of dimensions. Single items are
called scalars, and have rank 0. Vectors are zero or more items ordered
in a row, and have rank 1. A matrix has rows and columns, and has rank
2. Higher ranked arrays are just called arrays.
Arrays are named and given data values with the assignment function,
which is a left arrow in standard APL, and the pound sign (#) in
CAPLIB2:
" a becomes the scalar 3
a # 3
" b becomes the vector 1 3 5
b # 1 3 5
" c becomes the character vector 'abc'
c # 'abc'
" a becomes a new vector and is displayed
L # a # a + b
4 6 8
" d becomes a nested vector and is displayed
L # d # ('apples' 'oranges' 'pears'),[.5]a
apples oranges pears
8 12 16
Several important concepts are demonstrated in the last APL statement
above:
-> APL statements are evaluated right to left, and there is no
operator precedence, such as multiplication being done before
addition. However, there are binding strengths, discussed later,
and parentheses make associations explicitly.
-> APL arrays can change their data values, just like many other
programming languages, but what is more unusual is that they
can change their shape. In this case variable a changed from a
scalar of rank 0 to a vector or rank 1, dimension 3.
-> You can insert "L#" anywhere in an APL statement to display
results to that point. L is the caplib symbol for the APL quad
symbol.
..........................................................................
Mixing Data Types
In classic APL, an array could consist of either numeric or character
data, not both. An enhancement in APL2 and in CAPLIB2 allows a
mixture. Here's a matrix named m with five rows and three columns.
Each item in the first row and column, along with the last item in the last
row and column, contain character vectors. The rest of the data items
are all numeric scalars:
m
food calories protein
milk 160 9
apple 60 1
bread 75 2
jelly 50 none
..........................................................................
Depth
Depth measures the "deepest" you may go in selecting items of an array
before arriving only at a simple scalar. Consider the matrix m above.
Begin with a depth counter set to 0. m is not itself a simple scalar,
so add 1 to the depth counter, and select the vector `food' next for
consideration. `food' isn't a scalar either so add 1 again to the depth
counter, and select `f' from `food'. 'f' is a simple scalar, so depth
counter, which now contains 2, shows the depth of m.
There's a primitive function that produces depth, invoked with the equal
underbar symbol in APL2, and with the accented equal symbol (`=) in
CAPLIB2. For instance the CAPLIB2 expression -
apl> `= m
produces 2 for the matrix m shown above.
..........................................................................
Display Function
A way of graphically portraying the depth of an array, along with other
information, is with a defined function (defined functions are further
described below). called "display." It's distributed with IBM's APL2
Program Product. Output is a character matrix showing the data from its
array argument contained in a series of nested boxes, with symbols in
the borders that indicate the rank of the array, its data types, and
possibly whether it's nested.
When you trace your pencil from the outside of the output to an item,
without entering any boxes unnecessarily, the number of lines crossed is
the depth of that item. The depth of the entire array is equal to the
maximum number of lines crossed to an item using this rule. In the
followng two examples, the depths are 2 and 3:
apl> display 1 2 'more' (3 'a') (2 2RI4) 'b'
+$---------------------------+
| +$---+ +$----+ +$--+ |
| 1 2 |more| | 3 a | U1 2| b |
| +----+ ++----+ |3 4| - |
| +~--+ |
+E---------------------------+
apl> display 1 2 'more' (3 'or') (2 2RI4) 'b'
+$------------------------------+
| +$---+ +$-------+ +$--+ |
| 1 2 |more| | +$-+ | U1 2| b |
| +----+ | 3 |or| | |3 4| - |
| | +--+ | +~--+ |
| +E-------+ |
+E------------------------------+
The source for the display function, in CAPLIB2 format, is in
cap2/help/display.txt. Below is a table showing what the symbols in
the margins of the display output mean:
1) The output of the DISPLAY function is a series of nested
boxes containing the formatted items from the array.
2) The top and left borders of each box display symbols that
indicate the rank of the array. Lack of a symbol in the top and
left borders indicates a scalar.
3) Symbols in the bottom border indicate either the type of data,
or that the array is nested.
4) Border Symbols of the DISPLAY function
Symbol Meaning
$ At least a vector
U Matrix or array
O or @ Empty along this axis
~ Numeric
+ Mixed character and Numeric
no symbol Character
E Nested
- Scalar blank
..........................................................................
Data Constants
Constants in APL can be scalars or vectors consisting of character and
numeric data. Numeric constants can be integers, fractional real or
complex numbers. The following statement assigns to variable a a vector
consisting of two integers (1 and 400,000), a real fractional number
(2.3), a complex number (6i7), and a 3-element character vector ('abc'):
apl> a # 1 4e5 2.3 6j7 'abc'}
..........................................................................
Vector Notation
In classic APL, you could produce a vector by justaposing scalar
constants, as in -
apl> R a # 1 3 9 11 32
5
APL2 extends this with Vector Notation, where if you juxtapose a mixture
of two or more arrays or constants in an expression, the result is a
vector:
apl> R 2 6 'd' 4 'w'
5
apl> a # 1 2 3
apl> L # d # 'abc' a
abc 1 2 3
apl> Rd
2
apl> b # 3 4RI12
apl> L # c # a b
1 2 3 1 2 3 4
5 6 7 8
9 10 11 12
apl> Rc
2
You control nesting in Vector Notation by grouping items with parentheses
and quote marks:
apl> L # a # (1 2 3) (4 5 6) (7 8)
1 2 3 4 5 6 7 8
apl> R a
3
apl> L # b # 'red' 'white' 'blue'
red white blue
apl> R b
3
apl> L # c # (9 7 4) 'box' (7 'f' 9 'g')
9 7 4 box 7 f 9 g
apl> R c
3
apl> L # d # ('up' 'up') 'and' 'away'
up up and away
apl> R d
3
..........................................................................
Number Display
There are several ways you can control the display of numbers in
CAPLIB2. Unless you tell it otherwise, CAPLIB2 makes a best effort to
display numbers in a reasonable fashion. Most obviously, it eliminates
leading zeros to the left of the decimal point and trailing zeros to the
right of the decimal point. Slightly more subtle is its printing
reasonable numbers of significant digits. With pi (3.14159...) for
example, you have to stop somewhere to the right of the decimal.
CAPLIB2 by default does so after seven digits:
apl>O1
3.1415927
You can override by altering Print Precision:
apl>Lpp#5
apl>O1
3.1416
Or, you can tell the interpreter explicity how many significant digits
using the format function, subject to the limitations of the computer
architecture:
apl>15 13 F O1
3.1415926535898
CAPLIB2 will print numbers in scaled form according to a set of rules
that are slightly different from IBM's APL2:
1) Any number that needs more than 15 positions to print in conventional
form will be printed in scaled notation:
apl> 10 X 12345678901234 123456789012345
123456789012340 1.23457e15
2) Any fractional number for which the number of digits left of the
decimal is zero, and the number of zeros to the right of the decimal
point before the first significant digit exceeds Lpp, will be printed in
scaled notation:
apl>L#a#1.23456 0.1234 0.12345 0.000123 0.0000123
1.23456 0.1234 0.12345 0.000123 0.0000123
apl>Lpp#4
apl>a
1.235 0.1234 0.1235 0.0001 1.23e-5
..........................................................................
Alignment of Columns of Numbers
With IBM's APL2, decimal points, the E in scaled notation, and the J
for complex numbers align in columns. CAPLIB2 doesn't do quite as good
a job. It'll align decimal points in an array of purely real numbers,
but when complex numbers are involved, it simply ensures the columns line
up left justified:
apl>3 2 R 1 2.3 1.2 12.34 0.1 5.6
1.0 2.30
1.2 12.34
.1 5.60
apl>2 4 R 1 12.3 345 6j7 .1 .12 1j2 16j6
1.0 12.30 345 6j7
.1 0.12 1j2 16j6
..........................................................................
Character Vector Display
Simple character vectors are printed contiguously, and nested arrays
are indented:
apl>L#a#'f' 'a' 'c' 'e'
face
apl>`=a
1
apl>L#c#'f' 'a' 'ce'
fa ce
apl>`=c
2
..........................................................................
Array Display
A simple matrix is displayed as a rectangular plane:
apl>3 4 R I 12
1 2 3 4
5 6 7 8
9 10 11 12
Arrays of more than two dimensions are displayed as though they were
collections of two-dimensional rectangular planes, with numbers of blank
lines interspersed to indicate shape. A three-dimensional array, for
example, has a blank line separating each successive rectangular plane:
apl>2 3 4 R I 24
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20
21 22 23 24
For arrays of more than three dimensions, an additional blank line
separates planes of each dimension, so that one blank line separates
planes in the third lowest dimension, two blank lines separate planes in
the fourth lowest dimension, etc:
apl>2 2 2 3 R I 24
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
16 17 18
19 20 21
22 23 24
..........................................................................
Binding Strengths
As indicated previously, all functions execute according to their
position. The rightmost function whose arguments are available is
evaluated first. This is the right-to-left rule: So, if you're new to
APL, and you're used to multiplication taking precedence over addition,
you're likely to make the mistake of expecting 2 X 3 + 4 to evaluate to
10 instead of 14.
The right-to-left rule doesn't cover all situations. Should +.X/a b c
be evaluated as (+.X)/(a b c) or (+.X)/a (b c), or one of the other
possible bindings? In other words, given three names or symbols, how is
it determined if the center one is associated with the name or symbol on
the left or right? In APL2, a hierarchical set of binding strength
rules gives the answer. Each of the binding strengths in this table are
discussed in a following section:
Hierarchy of Binding Strengths
Binding Strength What is Bound
---------------------- ---------------------------------
Brackets Brackets to what is on their left
Specification left Left arrow to what is on its left
Right operand Dyadic operator to its right operand
Vector Array to an array
Left operand Function to its left argument
Left argument Function to its left argument
Right argument Function to its right argument
Specification right Left arrow to what is on its right.
Note 1: For binding, the branch right arrow behaves as a monadic function.
Note 2: Brackets and monadic operatos have no binding strength on the right.
Note 3: Parentheses override the default binding.
..........................................................................
Binding Strengths and Brackets
Brackets have the highest binding strength. They indicate indexing if
the object to their left is an array, and axis if the object to their
left is a function or operator. Given -
apl>a#'hat'
apl>b#4 8 10
apl>c#'w' 2 'x' 7
then because of binding strength, these two apl statements have the same
result:
apl>a b c[2]
hat 4 8 10 2
apl>a b (c[2])
hat 4 8 10 2
..........................................................................
Binding Strengths and Specification, Left
After brackets, the binding strength of specification (#) to the object
on its left is the next highest:
apl>a#2 3 4
apl>a[3]#'H'
apl>a
2 3 H
Given -
apl>a#2 3 4
apl>b#8
apl>c#'new'
these two statements produce the same result -
apl>a b#c
2 3 4 new
apl>a (b#c)
2 3 4 new
and in both cases b would be:
apl>b
new
..........................................................................
Binding Strengths and Right Operand
The right operand of a dyadic operator has the third highest binding
strength, to its operator. Given -
apl>a#2 3RI6
apl>b#3 2RI6
apl>c#2 2RI4
Then these two statements product the same answer:
apl>+.X/a b c
106 156
241 354
apl>(+.X)/a b c
106 156
241 354
Note that a right operand is never an array. No primitive dyadic
operators take an array right operand. This statement, which attempts
to force a dyadic operator to accept an array as right operand produces
an error:
apl>+.(X/(a b c))
+.(X/(a b c))
^ 63 - missing operator/function during execute processing.
..........................................................................
Binding Strengths and Vector Notation
The fourth highest binding strength is given to vector binding, which is
vector notation in which two arrays are written next to each other.
Here the first two APL statements are equivalent to the second two:
apl>2 1 3 / 2 3 4
2 2 3 4 4 4
apl>1 2 + 3 4
4 6
apl>(2 1 3) / (2 3 4)
2 2 3 4 4 4
apl>(1 2) + (3 4)
4 6
..........................................................................
Binding Strengths and Left Operand
The fifth highest binding strength is given to the left operand with its
operator. Because of its higher binding strength as right operand,
multiply (X) binds to the dot (.) in the expression +.X/ rather than to
the reduce /:
apl>+.X/(1 2 3) (4 5 6) (7 8 9)
732
apl>+.(X/(1 2 3) (4 5 6) (7 8 9))
+.(X/(1 2 3) (4 5 6) (7 8 9))
^ 63 - missing operator/function during execute processing.
apl>(+.X)/(1 2 3) (4 5 6) (7 8 9)
732
..........................................................................
Binding Strengths and Left and Right Arguments
Number six in binding strength is the left argument to its function,
followed by the binding strenth of the right argument, which is just a
restatement of the right-to-left rule:
apl>2 3 X 4 5 + 6 7
20 36
apl>2 3 X (4 5 + 6 7)
20 36
apl>(2 3 X 4 5) + 6 7
14 22
..........................................................................
Binding Strengths and Specification, Right
Lowest in binding strength is specification to what's on its right, so
that variable a in the following expression ends up a vector instead of
a scalar:
apl>L#a#1 2 3
1 2 3
..........................................................................
APL Functions
Functions accept arrays as arguments, producing new arrays as results.
Functions can be defined, derived, primitive, or system:
1) Defined functions are defined by you. They're the means by
which you "program" in APL.
2) Derived functions are produced by operators, described below.
3) Primitive functions, which are built in to APL, are
represented in APL statements by symbols, such as R for shape
and reshape. Primitive functions can be scalar or mixed.
4) System functions behave like primitive functions, and you use
them syntactically the same. Their names all begin with the
quad symbol (L for CAPLIB2). They all relate to the environment
in which you're working. Lcr for example gives you the
canonical representation of a defined function.
..........................................................................
Valence
Functions are also categorized according to their valence, or number of
arguments. Niladic functions have no arguments. Only defined functions
can be niladic, there being no primitives with this valence. Monadic
functions accept one argument, and dyadics accept two.
For monadics, the function symbol or name is to the left of its argument:
apl> R 1 2 3
3
For dyadics, the function symbol or name is between its arguments:
apl> 3 4 R 1 2 3
R above represents both monadic shape and dyadic reshape. It's called
ambi-valent, and the symbols used for all APL primitive functions have
this attribute. The context determines which is intended. As the
statements are scanned from right to left, in both cases above, first
the vector `1 2 3' is recognized, and then R is encountered. Whether
this is monadic shape or dyadic reshape is determined by whether a left
argument is next derived.
..........................................................................
Scalar Functions
Scalar functions apply to their arguments item-by-item, regardless of
their structure, and if they're dyadic (accepting two arguments),
they generally expect the arguments to be of identical rank and shape.
There is one exception to this rule: If one argument is a single item,
either a scalar or one-element vector, it will be replicated to match
the number of items in the other argument. Generally, scalar functions
yield results with shapes identical to their arguments. Addition,
multiplication, and division are examples of scalar functions. There
are only two scalar functions that accept character data arguments.
They are the comparisons equal and not equal.
"addition subtraction multiplication
1 2 3 + 4 5 6 1 2 3 _ 4 5 6 1 2 3 X 4 5 6
5 7 9 -3 -3 -3 4 10 18
"floor ceiling reciprocal
D -3.14 2.718 S -3.14 2.718 % 4 -5
-4 2 -3 3 0.25 -0.2
'abc' = 'axc' 'abc' ^= 'axc'
1 0 1 0 1 0
..........................................................................
Mixed Functions
There can be two reasons why they might be called mixed functions.
First, where they're dyadic, the two arguments don't have to agree
either in shape or in data type. Usually the left argument is
numeric, giving instructions for manipulation of the right
argument, which can either be numeric or character.
"reshape shape
L # a # 2 3 R 1 2 R a
1 2 1 2 3
2 1 2
"index generator index of
I 5 'abcdef' I 'cad'
1 2 3 4 5 3 1 4
"take drop
3 Y 2 4 6 8 2 U 2 4 6 8
2 4 6 6 8
..........................................................................
Operators
Operators accept both arrays and functions, applying the functions
in special ways, producing new arrays as results. There are six
operators:
1) Reduction: Denoted by a slash (/), reduction accepts as its
left argument a scalar dyadic function, and as its right
argument a numeric array. It applies the function between
adjacent items in the array. If v is a vector +/v produces
the sum of all elements in v.
2) Scan: Denoted by a backslash or slope (\), scan is related to
the reduction operator. It also accepts as its left argument
a scalar dyadic function, and as its right argument a numeric
array. The result is equivalent to the catenation of the
results of applying the scalar dyadic function using reduction
over successively longer selections from the right argument
The expression X\2 3 4 produces the result 2 6 24, where 2 is
the result of X/2, 6 is from X/2 3, and 24 is from X/2 3 4.
3) Axis: Operators such as scan and reduction described above are
first defined for vectors, and then applied to arrays of higher
rank as though they were sets of vectors defined along a
particular dimension. For example, a matrix has two dimensions,
rows and columns, and can be considered as a set of vectors
either running along each row or down each column. The axis
operator is denoted by brackets enclosing an expression which
yields the index of the dimension along which the vector set is
defined. For example, if m is a matrix, +/[1]m denotes
reduction down each column, and +/[2]m reduction across each
row:
L # m # 2 3 R I 6 +/[1]m +/[2]m
1 2 3 5 7 9 6 15
4 5 6
4) Inner Product: The dot (.) denotes inner product. Its arguments
are two scalar dyadic functions and two arrays. One form, m+.Xn,
is commonly called the matrix product of linear algebra:
L # m # 2 2 R 2 3 4 5 L # n # 2 3 R 5 + I6
2 3 6 7 8
4 5 9 10 11
m +.X n
39 44 49
69 78 87
5) Outer Product: Accepting a primitive scalar dyadic function and
two arrays as arguments, outer product applies the function
between all possible combinations of items from the left array
argument with items from the right array argument:
1 2 3 J.X 1 2 3 4 5
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
6) Each: Accepts a function and either one or two arrays as arguments,
depending on whether the function is dyadic or monadic: If dyadic,
each applies the function to corresponding pairs of items of the two
arrays; If monadic, the function is applied to each item of the array.
..........................................................................
Workspaces
When you create named arrays and defined functions interactively in APL,
they're stored in memory in what is called the "active workspace."
Numerous workspaces can be stored on disk, any one of which you can load
into memory as the active workspace. You can modify variables and
defined functions while the workspace is in memory, then save it back
on disk. There are 16 APL System Commands, all prefixed with a right
parenthesis, for manipulating workspaces and their content:
1. )clear -- Clears out the active workspace. Expunges all variables
and defined functions so the workspace is empty.
2. )copy wsname object [object...] -- The named object(s) are copied
from the specified workspace named "wsname" on disk into the active
workspace.
3. )drop wsname -- The workspace named wsname is deleted from disk.
4. )erase [object...] -- The named object are expunged from the active
workspace.
5. )fns [a] -- Displays a list of defined functions in the active
workspace, starting with the optional letter indicated by [a].
6. )group grpname [grpname] [object...] -- The list of objects are
grouped so they can be easily referenced by the single name
grpname.
7. )grp grpname -- Displays the membership of the named group.
8. )grps [a] -- Displays the groups in the active workspace, in
alphabetical order, optionally starting with the letter indicated
by "a".
9. )load wsname -- Workspace "wsname" is loaded into memory as the
active workspace.
10. )off -- Leave the interactive APL interpreter, and return to DOS.
11. )pcopy wsname object [object...] -- Identical in function to
)copy, except a named object will not be replaced if it already
exists in the active workspace.
12. )save [wsname] -- Saves the active workspace to disk with file
name "wsname.apl".
13. )si -- Displays the state indicator, showing halted defined
functions.
14. )sinl -- Same as )si, except local names are listed for each
defined function.
15. )vars [a] -- Displays a list of variables in the active
workspace, in alphabetical order, optionally starting with the
letter indicated by "a".
16. )wsid [wsname] -- If "wsname" is specified, it becomes the name
of the active workspace. Otherwise, the name of the active
workspace is displayed.
..........................................................................
User Defined Functions
A defined function is created by you, and is the means whereby you
"program" in APL. It consists of a function header followed by one or
more APL statements. Here's one called "plus" that returns the sum of
its two arguments:
" Lcr lists a character representation of a defined function
Lcr 'plus'
res # l plus r
res # l + r
1 + 2 + 3 1 + 2 plus 3
6 6
The first thing in a defined function is always a function header,
which begins with a template describing the function name and
arguments. This is analogous to the function declarator that appears
at the front of a program written in C. The template has one of six
forms:
Type With Result Without Result
Dyadic r # x f y x f y
Monadic r # f y f y
Niladic r # f f
where:
-> f is the name by which the defined function is known.
-> r is the localized name of the variable that will contain the
result. At least once during each execution of the defined
function, an assignment must be made to this name.
-> x is the localized name of the left argument of a dyadic defined
function.
-> y is the localized name of the right argument of a dyadic or
monadic defined function.
After the template describing the function name and arguments, you
can optionally include a list, delimited by semicolons, of names to
be localized. For example, the function header -
a demo b;c;d;e
declares demo to be a dyadic function returning no value, with left
and right arguments a and b, and three localized variables c, d, and
e.
..........................................................................
Branching
Defined functions can have numerous APL statements in them, normally
executed sequentially. You can change this order by inserting branch
statements, each comprised of a right arrow (this is a dollar sign,
$, in the CAPLIB2 symbol set) followed by an expression yielding a
scalar or vector. An empty vector means no branch will occur.
Execution continues with the next sequential statement. Otherwise,
the integer part of the leftmost or only value designates the next
statement to execute, according to these rules:
-> All statements in a defined function are sequentially numbered,
the function header being 0, the next statement 1, and so on.
-> If the integer derived from the branch statement is negative, 0,
or greater than the largest statement number in the defined
function, execution of the function terminates.
..........................................................................
State Indicator
)Si displays the state indicator, the stack of halted, i.e. suspended
and pendent, functions. Their names are listed in order, the most
recently halted first. Each is followed by the bracketed statement
number that was about to be, or was being, executed when the function
was halted.
Functions are halted either by an error, such as an attempt to divide
by zero, or by the stop control discussed below. They're called
suspended when this happens, and are flagged in the state indicator
list by *.
Pendent functions, those without * next to their names in the state
indicator, are there because they've invoked another function that
either got suspended, or became pendent by calling another function,
and so forth until one finally did get suspended.
When a function gets suspended you get control at the terminal. You
can enter pretty much any statement you like. You can clear functions
on the state indicator from the last to the preceding suspension by
entering a right arrow ($). Or you can branch anywhere in the topmost
suspended function by entering a right arrow followed by the statement
number to branch to.
You can resume execution at the point of suspension by branching to an
empty vector ($ I0), or to the line counter, Llc. This is a system
global variable that is a vector holding the current statement numbers
of the functions on the state indicator, in the same order, i.e., the
most recently halted leftmost.
..........................................................................
Stop Control
For debugging purposes, you can stop any defined function and receive
control just before any particular statement gets executed. To stop
defined function demo before lines 5 and 9 are executed, for example,
enter the APL statement -
sHdemo # 5 9
You'll receive control in the localized environment of demo. If it
localized variables a and b, then you'll have access only to those local
instances of a and b (other, global variables, are still accessible).
You can interrogate and change any variable you have access to. You can
resume execution at any statement n in demo by entering $n, or you can
terminate demo's execution by entering $0.
..........................................................................
Trace Control
For debugging purposes, you can trace any statement in a defined
function. You'll receive a report on your display each time a
designated statement in a defined function is executed. To trace
lines 1 thru 5 in defined function demo, for example, enter the
APL statement -
tHdemo # I5
The function name, the number of the statement in brackets, and the
final value of the statement is displayed each time it is executed.
A branch statement is indicated by a right arrow ($ in CAPLIB2)
followed by the number of the next statement to be executed.
..........................................................................
Del Editor Sample Session
Part of the standard APL system is a component called the "Del editor".
It's rather crude by today's standards. It worked great when the only
terminals available were teletypes. This sample session begins by
creating a defined function called sum:
The APL interpreter prompts with "APL>". I tell it I want to enter the
del editor for function sum:
APL> Gsum
[1]
The editor generally prompts for input by displaying the bracketed
statement number it expects you to enter next. In this case it has
prompted me to enter statement [1]. Because the function is new, the
editor assumes I entered the function header when I entered "Gsum".
It thinks sum is going to be niladic without a returned value. That's
not the case, so I tell it I want to re-enter the function header by
keying [0]:
[1] [0]
The editor prompts me with [0] and I supply the new function header for
sum:
[0] z # sum x
The editor prompts me with the next sequential statement number, and I
respond with the statement:
[1] z # + / x
The editor prompts me with the next sequential statement number. I ask
to see the entire defined function:
[2] [L]
G z#sum x
[1] z#+/x
G
[2] G
APL>
The editor displays the entire function, placing a G in front of the
function header and after the last statement. It also lists bracketed
statement numbers at the left margin. Finally it prompts me again to
enter statement 2, to which I respond "G" to tell it I'm done editing,
and I'm once again prompted with "APL>".
..........................................................................
Inserting a Statement
Suppose I want to add a comment to defined function sum telling what it
does:
APL> Gsum
[2] [0.1] " provides vector sums
[0.11] [L]
G z#sum x
[0.1] " provides vector sums
[1] z#+/x
G
[2] G
APL>
..........................................................................
Deleting a Statement
Then I change my mind and decide to delete the comment, displaying the
entire function before and after:
APL> Gsum[L]
G z#sum x
[1] " provides vector sums
[2] z#+/x
G
[3] [H1]
[3] [L]
G z#sum x
[2] z#+/x
G
[3] G
APL>
..........................................................................
Editing Statements
Now I'll use the statement editing capabilities to transform sum into
defined function mean:
APL> Gsum[L]
G z#sum x
[1] z#+/x
G
First there's the replacement of the function header:
[2] [0]
[0] z#mean x
[0.1]
Now to change statement [1] so it produces the vector means rather
than the sums:
[0.1] [1L0]
[1] z#+/x
Entering "[1L0]" above told the editor to display statement [1] with
the cursor positioned at the end of the statement, but one line lower
on the display. With standard APL, now you're expected to position
the cursor and key in letters or decimal digits indicating where you
want blanks inserted in the statement, and how many. Keying a "/"
means delete the character in the statement at that position. You can
use this if you want to, it'll work. But I just press Enter at this
point.
The editor responds by re-displaying the statement with the cursor
positioned on the same line at the right end of the statement. I
deliberately key an unmatched left parenthesis to get the editor to
issue the "unbalanced parenthesis" message and enter a special edit
mode which is not standard APL. In this mode:
-> The left and right arrow keys on the PC keyboard move the cursor
to new positions in the statement, without changing anything.
-> The Backspace key moves the cursor left, and at the same time
deletes a character.
-> Pressing any of the alphanumeric keys, e.g. ``K'', inserts that
character in the statement at the cursor position, and the cursor
is shifted right one position.
[1] z#+/x(
[1] z#+/x(
^ unbalanced parentheses
[1] z#(+/x)%-1Y1,Rx
[2] G
APL>
Now let's try the new mean function to see if it works:
APL> Gmean[L]G
[0] G z#mean x
[1] z#(+/x)%-1Y1,Rx
G
APL> mean 1 2 3 4 5
3
APL> mean 5
5
..........................................................................
Executing APL statements from a Linux or DOS file.
You can execute APL statements other than through the keyboard by
first storing them in a text file, named "stmts.tex" for example,
then using pipelining:
apl < stmts.tex
Incidentally, you can redirect the output to a printer under DOS in the
same fashion:
apl < stmts.tex > prn
Be sure to conclude your text file with an )OFF statement.
..........................................................................
Validation and Source Code Changes
Should you decide to make additions or changes to the source, there are
two important points to remember:
1) Remember the rules of the GNU General Public License, and clearly
document your changes.
2) I highly recommend your changes be backward compatible. There's a
shell script, cap2/bat/validate, that executes thousands of APL
statements, comparing the results against expected output. I, for one,
would not be interested in any changes that prevent this validation
process from completing successfully.
This concludes this READ.ME file.