Metropoli BBS
VIEWER: read.me MODE: TEXT (ASCII)
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.
[ RETURN TO DIRECTORY ]