"Learn APL" Notes
I use this page as reference card when I have any doubts about the APL language.
This file follows APL Wiki's APL Tutorial and Further Topics in APL guides, plus occasional extra looks at TryAPL for missing stuff on certain symbols (I made sure it was compatible with GNU APL).
I do not guarantee a comprehensive guide to APL here. This is mainly for future consulting.
Plus, make sure you are using a monospace font which supports APL characters!
Also see the GNU APL Manual.
Back to last page
Table of Contents
- Getting Started
- APL Concepts
- Further Topics in APL
- Finishing
Getting Started
Startup
Let's make sure our file executes. Executing the tangled file will run everything done in the tutorial.
Also, for live interaction, use gnu-apl-interactive-send-*
.
#!/usr/bin/apl --id 1010
Oh, and just so you know, use a unicode font which supports this stuff.
Simple arithmetic
Use ⍝
at the beginning of any comment.
⍝⍝⍝ Getting started ⍝⍝ This is a comment. ⍝⍝ Check the GNU APL keyboard for shortcut hints ⍝⍝ at any time. ⍝ Simple Arithmetic
Arithmetic functions
5+12 18÷3 108÷11 4×7 3.893×7.6
Use -
for subtraction, and ¯
for negative signal.
100-95 8-16
Arithmetic on lists of numbers
3+2 4 11 7 5
Spot the difference on applying a sum to each element and applying a sum on two numbers:
1+2 3 4 1+234
Lists can be on either side of the sign.
6 3 8 1+3 2.5 33.7 12 8÷15 9.8 11.2 17 1.2×1.175
It is possible to perform arithmetic between two lists in a per-element basis, but only if their length matches.
12 3 29 4×1 3 5 2
Order of execution
APL runs stuff from right to left, since there are so many functions on the language.
3×3-1
That is because APL groups things from right to left as well.
2 3 1+8÷2 2 2
If you need to make things unambiguous, use parentheses.
(2 3 1+8)÷2 2 2
Remember again the difference between -
and ¯
!
1985 - 1066 ⍝ Difference of two numbers 3 ¯1 ¯7 + ¯4 ¯1 2 ⍝ Sum between two lists with negative numbers 2-3+5 ⍝ This does 3+5, then does 2-8 2 ¯3+5 ⍝ This adds 5 to the number list 2 ¯3
Dual-purpose functions
Some functions can be used for more than one purpose.
When used in infix notation, ordinary operations have their intended effect:
5+4 1 3 4+3 1 6
You can, however, use the functions in prefix notation, which will change their effect.
+
appears to do nothing. Its true usage happens for assignment, which
we'll see next.
+12
-
inverts the signal of al numbers on the list.
- 3 ¯6 ¯8 4 12 ¯9
÷
takes the reciprocal of all numbers (divides 1 by them).
÷1 2 4 10 100
×
takes the sign of each number from the list. Yields 1
for positive
numbers, ¯1
for negative, and 0
for zero.
×8 0 ¯3 ¯7 0 4
There is no definition for postfix operators; that would be a syntax error.
Ceiling and floor
⌈
rounds a number up;⌊
rounds a number down.
To perform accurate rounding, you may want to use one of the following patterns:
⌈120.11 12.32 65.01 13.52 - 0.5 ⌊99.99 12.82 15.39 48.90 + 0.5
When using those operators under an infix form, ⌈
selects the greatest
number, while ⌊
selects the smallest number.
2 ⌈ 6 2 ⌊ 6
One can also use these operations to perform comparisions between lists of numbers.
6 8 1 ⌈ 3 5 9 6 8 1 ⌊ 3 5 9
Ending a session
If you want to end a session, use
)OFF
This will not be tangled.
Exercises
⍝ Exercises
- Q1
Enter statements to:
- Multiply each of three numbers,
3 6 2
by8
and then add4
to the results of the multiplication.
4 + 8 × 3 6 2
- Add 15% to each number in the list
14 5 78 145
.
1.15 × 14 5 78 145
- Add the difference between
13
and8
to4 6 12 7
.
(13 - 8) + 4 6 12 7 ⍝ Or... 4 6 12 7 + 13 - 8
- Multiply the result of
6
times3
by the result of4
times8
and subtract5
from the total.
((6 × 3) × (4 × 8)) - 5 ⍝ Or... ¯5+(6×3)×4×8
- Reverse the signs in this list:
3 ¯4 ¯12 6
- 3 ¯4 ¯12 6
- Compare these lists, selecting the larger number in each
comparision:
2 7 0 55
33 1 10 13
2 7 0 55 ⌈ 33 1 10 13
- Multiply each of three numbers,
- Q2
Which of these statements cause error messages? Why?
- Statement
a
is a valid multiplication between12
and9
. - Statement
b
is a valid sum between3
and¯2
. - Statement
c
produces aLENGTH ERROR
because19 0 3 4
and7 2 87
are lists of different lengths. 5 ¯8
is a valid list of two numbers; it may be unintended, though.
- Statement
- Q3
You're getting
£200
worth of dollars for yourself and£180
and£230
worth respectively for two friends. Enter a statement which calculates how many dollars each of you will get at1.96
dollars to the pound.200 180 230×1.96
- Q4
Highest recorded temperatures for a week in August were:
79 84 83 78 74 69 70
(Fahrenheit)
Enter a statement to convert them into Centigrade. (One method is to subtract 32 degrees and multiply by 5/9.) Suppress decimal places in the result.
⌊((79 84 83 78 74 69 70-32)×5÷9)+0.5 ⍝ Or... ⌈¯0.5+(5÷9)×79 84 83 78 74 69 70-32
- Q5
Enter a statement to find the difference in metres between 1500 metres and a mile. (1 yard = 0.9144m and 1760 yards in a mile)
¯1500+1760×0.9144
Variables
⍝ Variables
Assignments
An assignment can be done with a variable name and a ←
symbol.
A ← .175
This enables A
to be used in expressions.
200×A A×30.50 12.25 60.30 15.00 ⌈ A×30.50 12.25 60.30 15.00
C
is the conversion factor for fonverting pounds to kilograms.
C ← .45359237 17 × C ⍝ Convert 17 lbs into Kg ⌈C×11×14 ⍝ How many Kgs are there in 11 stones, ⍝ then round up
To keep a calculation, we then use variables.
JOE ← ⌈C×11×14
Variable names
Valid statements:
AAA ← 4 ab ← 1 C9999 ← 0 Jack_Smith ← 100
Which denotes that APL is case sensitive.
Also, APL doesn't have bare words as variable names:
JOHN SMITH ← 100
However, using parentheses will create two identical variables with the same value. This happens in both GNU APL and Dyalog.
(JOHN SMITH) ← 100 ⍝ Creates JOHN with value 100 ⍝ and SMITH with value 100
And if you start a variable name with a single number, the number will be printed right after the value, which is assigned to the variable name that follows:
5B ← 12
Assigning lists to variables
PRICE ← 12.45 5.60 5.99 7.75 +VAT ← PRICE × A ⍝ A was assigned earlier
The +
operator, when put before an assignment, forces a declarative
behaviour on the assigned variable – in other words, forces the
variable to be displayed.
Using an unassigned variable causes a VALUE ERROR
.
System commands
The )OFF
command has already been presented earlier.
)VARS
lists all variables in the workspace.
)VARS
)WSID
shows the identity of the current workspace, which defaults to
CLEAR WS
.
)WSID
This command can also be used to change the identity of the
workspace; we change its name to NEW
. The variables in it won't
change.
)WSID NEW
To remove the variables (and the name), we can use )CLEAR
.
)CLEAR
Character assignments
APL doesn't only deals with numbers, it can also deal with text. Just apply quotes.
A ← 'APL WILL PROCESS TEXT' C ← 'CHARACTERS'
To insert quotes inside the text, use ''
.
NAME ← 'WHAT''S IN A NAME? '
Other way to do that is by using double quotes around the characters.
NAME ← "WHAT'S IN A NAME? "
Consider the following variables.
N ← 'NET PRICE' QTY ← '230'
Attempting to perform arithmetic on text generates a DOMAIN ERROR
:
N×10
QTY+5
Multiple assignments
One can assign one value to multiple variables at the same time:
(ZAK YAK) ← 5
Or assign many values to many variables at the same time too:
(YEN MARK BUCK) ← 10 20 30
Displaying variables together
This part is straightforward.
N 10 NAME C X ← 18 Y ← 3 1985 X Y NAME X C 'NET PRICE: ' 10
Joining lists
When writing X Y
, these values were joined in a list of two
elements. The first element was the number in X
, the second was the
two-element list in Y
.
Let's store this result.
Z ← X Y
Operations done in Z
will not affect X
and Y
(also notice how +10
maps
elegantly into sublists!!!):
Z ← Z+10
Example with characters.
CNAME ← 'BASIL ' SNAME ← 'BRUSH' NAME ← CNAME SNAME
Notice, though, that NAME
is a list of two elements, each being a list
of characters; this is called a nested variable.
Joining and merging variables
The comma (,
) allows APL to catenate lists.
NAME ← CNAME,SNAME
One can see that the variable indeed became a non-nested list of 11 characters.
⍴NAME
Simple and nested variables
Single numbers (separated by spaces) and characters make up lists.
PIERRE ← 1 2 3 4 MIREILLE ← 'FILLE'
Numbers enclosed in parentheses are treated as single items, so now
PIERRE
will be a list, containing two lists.
PIERRE ← (1 2 3) (4 5 6 7)
A list of character lists is easier, just enclose each sublist in quotes (if you were to put it in a single, simple list, you'd put everyone under the same quotes anyway):
FRANCOISE ← 'UNE' 'JEUNE' 'FILLE'
Mixed variables
This is not good for arithmetic, but it's useful to store characters and numbers together.
PHONES ← 'BILL' 577332 'FRANK' 886331
Exercises
Let's start with a clean workspace.
)CLEAR
- Q1
Enter statements which:
- Assign the numbers
22 2 2007
to three variables called respectivelyD
,M
andY
.
(D M Y) ← 22 2 2007
- Assign the characters
TODAY'S DATE:
to a variable calledDATE
.
DATE ← 'TODAY''S DATE: '
- Produce the display:
TODAY'S DATE: 22 2 2007
DATE D M Y
- Assign the numbers
- Q2
Set up a variable
CONV
which contains a constant for converting pounds to kilos. (1lb = 0.454Kg and 14lb = 1 stone). UseCONV
to convert your weight (to the nearest stone) into kilograms. Reduce the result by 10%, round it down, and display it.⍝ 1 stone = 14 lbs. ⍝ 1 lb = 0.454 Kg. ⍝ Let's pretend I weight 11.5 stones. CONV ← .454 MYWEIGHT ← ⌊11.5×CONV×14×.9 MYWEIGHT
- Q3
The cost prices of four items of stock are £8, 6, 12, 4 respectively. The markup on these items is 100%. Three other items cost respectively £16, 13 and 7. Their markup is 75%. Calculate the fully inclusive price of each item (with VAT at 17%). Display the prices (rounded up) with the caption:
'PRICE+VAT: '
ITEMS_A ← 2×8 6 12 4 ITEMS_B ← 1.75×16 13 7 ITEMS ← ⌈1.17×ITEMS_A,ITEMS_B 'PRICE+VAT: ' ITEMS
- Q4
TEST1
contains a student's exam marks for each of seven subjects (65 72 54 80 67 60 59).TEST2
contains his marks for the same subjects gained at a different test (75 70 60 74 58 61 50). Produce a list consisting of his higher mark for each subject.TEST1 ← 65 72 54 80 67 60 59 TEST2 ← 75 70 60 74 58 61 50 TEST1 ⌈ TEST2
- Q5
Which of the following will produce error messages? Why?
- The expression
RATE ← '3.7×3'
is a valid assignment of a list of characters, though it might be a logic error. - The expression
10+10 '←21'
produces aDOMAIN ERROR
, because it tries to sum10
over a list containing the number10
and the list of characters'←21'
, which cannot perform arithmetic operations. - The expression
100×RATE
produces aDOMAIN ERROR
, because it tries to multiply by100
over a list containing characters (RATE
), which cannot perform arithmetic operations. - The expression
SYMBOLS ← '¯<≤=≥'
is perfectly valid and creates a list of characters. But it might not be supported by some APL implementations (GNU APL supports it). - The expression
3+'232'
produces aDOMAIN ERROR
, because it tries to sum3
over a list of characters, which cannot perform arithmetic operations.
- The expression
Cleanup
From now on, we clear the variables and the workspace across chapters.
)CLEAR
Tables
We won't be typing a lot of things here, that is insane! Let's see how to generate our tables.
⍝ Tables
The Roll function
?
is the Roll function, also called Random or Deal.
This generates numbers on range 1 to 100:
? 100
The two-argument form generates a list of n
(left) unique numbers from
1 to m
(right):
50 ? 100
In fact, it should always be true that n ≤ m
, since the generated
numbers are unique. If not, we'll have a DOMAIN ERROR
.
Both n
and m
can be replaced by variables as well.
The Iota function
Iota, or Index, generates a sequence of numbers from 1 to m
in its
one-argument form.
⍳100
Setting up tables
When entering tables, we use dyadic for of the rho (⍴
) function, also
called Shape or Reshape. The list before ⍴
states the order of the
table; the following elements are its rows, element by element.
4 3 ⍴ 10 20 30 40 50 60 70 80 90 100 110 120
Let's generate twelve random numbers, then display them in a 4×3 table.
DATA ← 12 ? 100 4 3 ⍴ DATA
If you feed ⍴
less numbers than expected, APL just keeps wrapping
these numbers. If you feed more than expected, APL uses just enough
numbers to build the table.
4 3 ⍴ 1 2 3 4 5
And so follows that supplying one number fills the whole table:
3 5 ⍴ 1
- Extra bit
I wonder about identity matrices! Let's take a 3×3 matrix. If we type a
1
, and then a numbern
of zeroes (corresponding to the matrix order), then I suppose we can build an identity matrix…3 3 ⍴ 1 0 0 0
Indeed! But wait: I don't know how to build functions in APL yet, but I suppose we can take this arbitrary number of zeroes and write them in ⍴-notation too.
- Generate a list of
n
zeroes; - Catenate a number
1
in front of it; - Feed it as filling elements to the second ⍴.
4 4 ⍴ 1,(4 ⍴ 0)
- Generate a list of
Arithmetic on tables
Let's begin.
SALES ← 3 3⍴20 13 8 30 43 48 3 50 21 SALES
Performing arithmetic on a table affects every number, just like in a list.
SALES×10
Let's set up another table.
PRICES ← 2 3 ⍴ 21 2 12 47 33 1
This operation causes a LENGTH ERROR
:
SALES×PRICES
This is because SALES
is 3×3 while PRICES
is 2×3. So let's reshape
SALES
into a 3×2 table. This way, both of them will have the same
number of elements.
SALES ← 3 2⍴SALES
But that still won't do… we're trying to multiply elements of same address here, not make matrix multiplication. Let's try again.
SALES ← 2 3⍴SALES
Ok, now we're good and we can proceed.
TOTAL ← SALES×PRICES SALES-PRICES
- Extra bits
Let's build a nice table.
First table:
- Build a sequence from
1
to25
. - Create a
5×5
table with it. - Take the reciprocal of each number.
- Multiply each element by
10
.
Second table:
- Take a sequence from
1
to25
. - Add
25
to each element. - Create a
5×5
table with it.
Final table:
- Multiply each element of first table by each element of second table.
- Round every number by adding
¯.5
to each number and taking their ceiling.
TOTAL ← ⌈¯.5+(5 5⍴25+⍳25)×10×÷5 5⍴⍳25
- Build a sequence from
Catenating tables
Catenating tables produce a big table. Each row is catenated like a list. Therefore, catenated tables must have the same number of rows.
SALES,PRICES
Let's test it a little more.
LITTLE ← 2 2⍴1 MEDIUM ← 2 6⍴5 BIG ← LITTLE,MEDIUM
To perform LITTLE+MEDIUM
, we pad LITTLE
with a table of zeroes.
ZEROES ← 2 4⍴0 LITTLE ← LITTLE,ZEROES LITTLE+MEDIUM
We could also have the zeroes on the other side; let's reset LITTLE
and do it.
LITTLE ← 2 2⍴1 LITTLE ← ZEROES,LITTLE LITTLE+MEDIUM
Since there is this kind of ambiguity, that is the reason why APL doesn't do arithmetic on data of unequal size.
Selecting elements
Let's set up a 4×3
table for the next example.
+TABLE ← 4 3⍴2 12 15 4 11 7 1 16 8 20 19 9
Let's select the 9
in the bottom row, rightmost column.
TABLE[4;3]
We sum the element at Row 1, Column 2 to the element at Row 2, Column 2. Then we put it on Row 3, Column 2:
TABLE[3;2] ← TABLE[1;2] + TABLE[2;2]
We can select more than one element in a row, or even in a column.
TABLE[1;1 2] TABLE[1 2;2]
To select entire rows or columns, omit the other parameter.
TABLE[1;] TABLE[;1]
Let's replace the numbers in column 3 with the sum of numbers in columns 1 and 2.
TABLE[;3] ← TABLE[;1] + TABLE[;2]
Also note that indexing can also be applied on lists.
LIST ← 8 1 90 4 LIST[2]
Dimensions
In APL, data has dimensions.
- Single numbers have dimension zero.
- A list has one dimension.
- The previous tables have two dimensions.
- Three-dimensional tables/arrays are like cubes, having depth, height and length.
- It is possible to create arrays of many dimensions in APL.
SALES ← 6 4⍴24?50
In SALES
, the salesmen are rows, the products are columns.
If we wanted to represent more than one region – say, three regions
–, we'd need another dimension.
+SALES ← 3 6 4⍴72?100 SALES[2;5;4] ⍝ Plane 2, Row 5, Column 4 SALES[2;;] ⍝ Plane 2
Enquiring about the size of data
While the dyadic usage of ⍴
involves creating arrays, the monadic
usage of ⍴
allows one to enquire about the size (or shape) of existing
tables, variables, etc.
⍴SALES
Let's create some data.
TABLE ← 5 3⍴15?20 LIST ← ⍳6 NUM ← 234
Now let's ask about their shape.
⍴TABLE ⍴LIST ⍴NUM
Notice that, since NUM
has no shape (equivalent to a point), APL gives
an empty response.
We don't need variables to do this kind of thing, though. We can apply directly to literals.
⍴12 61 502 1 26 0 11 ⍴'SHAMBOLIOSIS'
Tables of characters
This is also straightforward; characters are stored as a list of characters. Let's do some experiments.
⍝ Compare these two. ALF ← 3 5⍴'ABCDE' NUM ← 3 5⍴12345 MYNAME ← 'GORSUCH' ⍴MYNAME 3 7⍴MYNAME 3 14⍴MYNAME 3 18⍴MYNAME MYNAME ← 'GORSUCH ' ⍴MYNAME 3 40⍴MYNAME
Solution for the given example.
4 11⍴'ADAMS CHATER PRENDERGASTLEE '
Mixed tables
We can build tables containing characters and numbers, just like the lists.
MIXTURE ← 3 3⍴'A' 1 'B' 'C' 2 'D' 'E' 3 'F'
Nested tables
Tables can contain other tables or lists.
NEST ← 2 3⍴(2 2⍴⍳4) (⍳5) 'A NAME' (2 4⍴⍳8) 23 (3 4⍴'NAME') ⍴NEST
Depth
The depth (≡
) function shows the degree of nesting in a variable.
≡45 ⍝ Values have depth 0 ≡1 2 3 ⍝ Lists have depth 1 ≡2 2⍴3 4 5 6 ⍝ Tables too
Now let's check the depth of NEST
:
≡NEST
When at least one element of a list or table is also a list or table, the depth becomes 2; and so on, as long as you have child list/tables inside child list/tables:
BIG_NEST ← NEST NEST ⍴BIG_NEST ≡BIG_NEST
Since the components of BIG_NEST
already have depth 2, BIG_NEST
adds
one more layer of depth.
Practice
Some interesting snippets showcasing the strength of APL: combining functions.
⍝ Playing with sizes of character lists (⍴'ABC','DEF')+⍴'GHI' ⍝ Selecting the first nine numbers in row 1 of a big table TABLE ← 10 10⍴100?100 TABLE[1;⍳9]
Exercises
)CLEAR
- Q1
Set up a four-row one-column table called
MILES
containing300 42 25 140
.MILES ← 4 1⍴300 42 25 140
And a similarly shaped table called
RATES
containing27.5 15 27.5 27.5
.RATES ← 4 1⍴27.5 15 27.5 27.5
Multiply
RATES
byMILES
, then multiply the result by0.01
to produce a table calledEXPENSES
.+EXPENSES ← .01×RATES×MILES
- Q2
Change the number in column 1 row 3 of
MILES
from25
to250
. Again, multiplyRATES
byMILES
and the result by0.01
to giveEXPENSES
, then reformatEXPENSES
to produce a one-row four-column table.MILES[3;1] ← 250 +EXPENSES ← (.01×RATES×MILES)[;1]
Alternative way to change
EXPENSES
; interesting way to store and immediately use a variable.+EXPENSES ← 1 4⍴EXPENSES ← .01×RATES×MILES
- Q3
Define
X
as a three-row ten-column table containing random numbers, andY
as a three-row four-column table also containing random numbers. AddX
toY
, first taking whatever steps you think necessary to enable the operation to take place.⍝ Defining the tables X ← 3 10⍴30?30 Y ← 3 4⍴30+12?12 ⍝ To sum Y into X, we catenate zeroes to Y, ⍝ extending it. X+Y,3 ((⍴X)[2]-(⍴Y)[2])⍴0
Since the problem did not specify where to add the columns, here is an alternative which catenates the zeroes to the left of
Y
:X+(3 ((⍴X)[2]-(⍴Y)[2])⍴0),Y
- Q4
Using table
X
, add the first and second rows and replace the third row with the result of the addition.X[3;] ← X[1;]+X[2;]
- Q5
Create a table which [displays
APL ROCKS
in vertical orientation]:9 1⍴'APL ROCKS'
- Q6
What will be the result of each of these
⍴
statements? Predict each result before you press ENTER.⍴'ABC DEF'
→7
⍴480 0 1.2
→3
TABLE ← 10 10⍴100⍴1000
⍴TABLE
→10 10
⍴'R'
→ (empty)⍴'480 0 1.2'
→9
TABLE ← 2 10 3⍴100⍴100
⍴TABLE
→2 10 3
NOTE: Recall why
⍴'R'
gives an empty response: a single value is equivalent to a point, which has no size/dimension/shape.
Cleanup
)CLEAR
Writing a function
⍝ Writing a function
Precondition: the Slash operator
The Slash (/
) or Reduce operator is not a function; it modifies or
extends the operation of the functions it is used with.
It works as if by putting the operator between the numbers.
+/ 1 6 3 4 ×/ 1 2 3 4
This can be done on a table too, however it will sum in a row basis.
TABLE ← 3 3⍴⍳9 TABLE +/ TABLE
We can, however, apply Reduce twice to obtain the entire sum.
+/+/ TABLE
Useful combination: To select the largest number in a list, use ⌈
:
⌈/ 75 72 78 90 69 77 81 88
The opposite equivalent (⌊
) selects the smallest number:
⌊/ 75 72 78 90 69 77 81 88
A final example: We take the sum of X
(which is 15
) and divide it by
X
's shape (5
). This yields 3
, as expected of calculating the average
of a number.
X ← ⍳5
(+/ X)÷⍴X
User functions
Now we'll preserve statements.
It seems some APL editors have a built-in editor. For example, one can use the following commands:
)EDIT MYFUNC ⍝ On modern editors )ED MYFUNC ⍝ On Dyalog ∇ ⍝ On older editors, and on GNU APL as well
GNU APL also calls a new buffer when defining a function, under
Emacs. We can also send the following region to the interpreter no
problem. We just need to type in the function (∇
) operator, which
starts the input mode.
Typing ∇
again goes back to calculator mode.
∇TRY1 'Type some numbers: ' NUM ← ⎕ ⍝ Asks for user input 'Total is: ' (+/ NUM) ∇
In case this function doesn't work when typing, just use ∇TRY1
to
change its definition on the editor.
This defines a user function TRY1
, which takes no arguments. The Quad
(⎕
) operator calls in for user input.
You can edit a function such as TRY1
anytime, by typing ∇TRY1
on the
REPL; other APL implementations will allow you to use the command
)EDIT TRY1
, for example.
Here is another example:
∇TRY2 'Type some numbers: ' NUM ← ⎕ 'You have entered' (⍴NUM) 'numbers' ∇
And as requested, here is a way to calculate the average of some numbers:
∇AVERAGE 'Type some numbers:' NUM ← ⎕ 'Integer average of these numbers is:' (⌊(+/ NUM)÷⍴NUM) ∇
One more definition.
∇TRY3 'Type some numbers:' NUM ← ⎕ 'You have entered' (⍴NUM) 'numbers' 'The biggest was' (⌈/ NUM) 'The smallest was' (⌊/ NUM) 'Sum of numbers is' (+/ NUM) 'Integer average of numbers is' (⌊(+/ NUM)÷⍴NUM) ∇
Saving a workspace
You can check out the user-defined functions in your workspace with this command:
)FNS
There are some extra variables as well (check by using )VARS
), so we
need to erase them:
)ERASE TABLE X
Now we'll save the current workspace. First let's set the workspace ID to the filename where it should be salved.
Notice that we are using Unix notation and the XML extension. This is a requirement for GNU APL.
)WSID ./MyFirstWS.xml
Windows users, using NARS2000, should do something like:
)WSID 'c:\foo\MyFirstWS'
Now we use the command to save.
)SAVE
My result was:
2019-08-06 12:56:35 (GMT-3) ./MyFirstWS.xml
Now we can safely clear the workspace.
)CLEAR
To load the workspace again, use the load command with the file name.
)LOAD ./MyFirstWS.xml
NOTE: GNU APL instructs to use )COPY
instead.
User functions with arguments
User functions can have no arguments, one argument or two arguments.
- Monadic
We intent to build a function which averages the numbers in a list. So let's define it.
∇AV X (+/ X)÷⍴X ∇
Now we can use it properly.
AV 12 7 3 1 AV 3 8 1 4 AV 192 4534 12 0 2 NUM ← ⍳5 AV NUM
- Dyadic
A dyadic function should be declared with arguments to its left and its right:
∇A SUM B A+B ∇
Using function results in other expressions
To do so, we need to rewrite the function to enable that. See this
rewriting of AV
.
∇R←AV X
R←(+/ X)÷⍴X
∇
An example of usage:
¯3 + AV 3 8 1 4
The same can be done to dyadic functions.
∇R←A SUM B
R←A+B
∇
Cleanup
)ERASE NUM )SAVE )CLEAR
APL Concepts
Overview of the APL System
APL is an interpreted language.
APL reserves an area in the RAM, which is called a workspace. This is were programs and data reside. Other workspaces can be loaded at will for calculation and processing.
Data
Data is acquired by typing or from files. All data is held in arrays or scalars.
GNU APL supports complex numbers.
Formal names will be used from now on.
Modes
APL uses a modal interpreter. Calculator mode executes statements as entered. Definition mode does not execute immediately, and stores statements as a user-defined function or operator. Function execution mode happens when you run a user-defined function or operator.
Built-in functions and operators
APL has about 50 built-in functions which can be invoked by a single symbol.
Most functions can perform two different opperations depending on whether they're used with one or two arguments.
APL also has five built-in operators. Combining an operator with its operands creates a derived function.
System functions and variables
Part of APL system, yet not part of APL language. Used to extend facilities provided by original APL, they vary from one vendor to another. Could also be tailored to the system which it is running.
System functions such as ⎕NREAD
and ⎕NWRITE
(with names starting with
a Quad ⎕
) read and write data from files, and are distinguishable from
the rest by their starting character.
System commands
They are also not part of the APL language itself, but are crucial to
managing the workspace. They always start with a )
.
User-defined functions and operators
Functions or operators which can be written by the user. Consists of APL statements that have a name. Functions are edited through the function editor, which can also be used to tweak a function.
Files
Files are usually not necessary on APL, given the convenience of workspaces, being only really required when dealing with big projects. When that time comes, APL has facilities for that; and workspaces can be shared between users.
Error handling
APL provides facilities for error trapping and diagnostics.
The Workspace
Workspaces are containers for functions and data, and can be saved on disk by using commands.
APL also makes it easy to create test data for functions. Since prototyping can be done so quickly, APL is sometimes referred to as a "tool of thought".
Functions, operators, classes
Functions can take 0, 1 or 2 arguments; arguments to functions are always arrays.
Operators look like functions, but takes either one or two operands,
which can be functions (e.g. the Each operator ¨
). They can also be
defined.
Classes are a collection of functions, operators and data (named properties). Acts as a template to create objects. Classes are supported in Dyalog, but not in GNU APL.
Workspace size
Some APLS allow changing the size of your workspace with )CLEAR 50MB
,
for example.
To check the amount of free space on your workspace, use the system function Workspace Available:
⎕WA
Managing the workspace
- Internal workspace commands
These have already been discussed.
)CLEAR
: Clear workspace. Erases all variables, functions, operators and classes.)ERASE
: Erases individual classes.)VARS
: Lists all user-defined variables in the workspace.)FNS
: Lists all user-defined functions in the workspace.)OPS
: Lists all user-defined operators in the workspace.)CLASSES
: Lists all user-defined classes in the workspace. Can be used in Dyalog.
- External workspace commands
Some of these have already been discussed.
)SAVE myWorkspace
saves a workspace to disk. Append.xml
if you're using GNU APL.)LOAD myWorkspace
loads an entire workspace back into memory; the workspace in memory is overwritten.)COPY
can be used to copy a function from a workspace in disk, but does not overwrite the current workspace.)DROP
deletes a workspace on disk.)LIB
shows the names of the workspaces stored on disk.
Save locations vary due to APL implementations.
System variables
Here are some useful system variables which you may use.
⎕WA
: Workspace Available. Number of available bytes for use in workspace.⎕PP
: Print Precision. Number of digits displayed in numeric output.⎕PW
: Print Width. Max number of characters in each printed line.⎕LX
: Latent Expression. This variable contains an expression or user-defined function which is executed when the workspace is loaded; effectively, a setup function for the current workspace. Empty by default.⎕IO
: Index Origin. Stores the value where indexes start. GNU APL starts at 1, but can be changed to 0.
System functions
These vary from vendor to vendor, so there is no guarantee that these will work in your APL. For example:
⎕NL
: Name List. Produces a list of variables, functions, operators or classes.⎕EX
: Expunge. Expunges individual APL objects.
System functions are designed to be used in user-defined commands, whereas system commands are designed for direct usage.
Data
⍝⍝⍝ APL Concepts ⍝ Data
Variables
Data can be directly quoted…
234.98×3409÷12.4
…or assigned to a name.
VAR ← 183.6
Names
APL allows uppercase and lowercase characters, some APLs also allows symbols too.
Types of data
Data can be numbers, characters or a mixture of those. GNU APL in particular also allows complex numbers; Dyalog allows classes.
Size, shape and depth
From now on, unless there is something new, only some examples will be typed.
⍝ Scalars (no dimensions) 294 'A' ⍝ Vectors (one dimension -- length) 23 8 0 12 3 'ABC' 28 3 'A' 'BC' ⍝ 2D Matrices (two dimensions -- height and length) ⍝ There is no way to write a matrix literal. 4 4⍴7 45 2 89 16 15 10 21 8 0 13 99 83 19 4 27 4 2⍴'WILSO' 393 'ADAMS' 7183 'CAIRN' 87 'SAMSO' 8467 ⍝ 3D Matrices (three dimensions) 3 3 4⍴36?100
Arrays are data structures of any dimension – obviously, scalars do not apply.
Setting up data structures
X1 ← 23 9 144 12 5 0 X2 ← 1 2 'A' 'B' 3 4 2 3⍴23 9 144 12 5 0 NUMS ← 36?100 3 3 4⍴NUMS 6⍴9 ⍝ Nested arrays VAR ← (2 3⍴9) (1 2 3) 'A' 'ABCD' 88 16.1
Data structure versus data value
X ← 1⍴22 Y ← 22 ⍴X ⍝ 1, because X is a vector ⍴Y ⍝ Empty response, because Y is a scalar Z ← 1 5⍴12 5 38 3 6 ⍝ When displayed, Z looks like a vector, ⍴Z ⍝ but is in fact a 1×5 matrix )CLEAR
Empty data structures
Useful for some things, for example flor predefined storage areas, where elements can be added.
X ← ⍳0 ⍝ X is a vector of zero elements X ⍝ Printing X gives an empty response ⍴X ⍝ Asking for the shape of X gives a zero
This is fundamentally different than a scalar, which does not have zero elements: a scalar has zero dimensions instead.
⍴45
We can also create empty matrices. For example, a matrix of two rows and no columns:
TAB ← 3 0⍴⍳0 TAB ⍴TAB
Dimension ordering
General rule when applying an operation to data (e.g. a reduce /
):
Unless specified otherwise, the operation takes place on the last dimension.
For example, consider a 3×4 matrix.
X ← 3 4⍴⍳12 +/ X
Applying a reduction to it yields a list of three elements. Each element of the list is the sum of a row. This is because a column is the last dimension of a 2D matrix (3 rows, 4 columns).
In other words, since we're performing the reduction on the last dimension (columns), then each result is the sum of all columns belonging to that row.
You can change that by using the axis ([]
) operator:
+/[1] X
This carries the reduction on the first axis (rows), therefore the resulting list of four numbers is the sum of each column.
Now each result is the sum of all rows belonging to that column.
)CLEAR
Indexing
There is something that remains to be discussed. Last section talked about the rows in index 1. This seems to mean that in APL indexes start at 1, but that might not be always true. This is true for GNU APL, to say the least.
If you wish to change indexing, just change the Index Origin system variable (this bit is not tangled):
⎕IO ← 0
From here on, we'll consider Index Origin to be 1
.
Selecting elements is easy. Just use the brackets ([]
), and separate
variable indexes with ;
.
⍝ Indexing in one dimension X ← 1 45 6 3 9 33 6 0 1 22 X[4] + X[10] ⍝ Indexing in two dimensions TABLE ← 3 3⍴9?100 TABLE[3;2] ⍝ Indexing for more than one dimension ⍝ Indexing in three dimensions DATA ← 4 4 4⍴64?100 DATA[2;1;4] ⍝ Selecting an entire row in tree ways TABLE[1;1 2 3] TABLE[1;⍳3] TABLE[1;] ⍝ Selecting an entire column TABLE[;2] ⍝ Selecting from anonymous data (3 8 4)[1+2] ⍝ Selecting from an anonymous string, based on a variable P ← 2 'ABCDE'[P]
Some useful stuff that has not been discussed yet:
Indexing can also be used to rearrange elements on a matrix!
'ABCDE'[4 5 1 4]
We can also do indexing with variables of a higher dimension. This pretty much collects stuff and stores it in the created shape:
'ABCDE'[2 2⍴4 5 1 4]
Indexing can also be done with the squad (⌷
) symbol (notice that this
is different from the quad ⎕
, since it is narrower):
2⌷'ABCD'
)CLEAR
Built-in functions
APL has 50 useful built-in functions in general, and 5 operators to modify and extend how functions work.
⍝ Built-in Functions
Arguments
Most functions have two behaviours depending on how you place their arguments. For example:
⌈12.625 ⍝ Ceiling 2⌈8 ⍝ Select greatest number ÷1 2 3 4 5 ⍝ Reciprocal 100÷1 2 3 4 5 ⍝ Divide 100 by each
Execution order
Expressions are evaluated from right to left. The results of one function become the argument of the next function.
Numbers or text
Some functions work on numbers only. Some work on either numbers or
text data. Using a function which does not work on a data type yields
a DOMAIN ERROR
.
Some functions also work only on a subset of the number domain, such
as logical functions (∨
, ∧
etc.) Thiis means that they only recognize
the states of TRUTH (1
) and FALSITY (0
).
Shape and size of data
Some functions can be used only on data of a certain shape. The
following example (not tangled) yields a LENGTH ERROR
, because data on
both sides do not have the same shape:
29 51 60 27÷3 11
Groups of functions
Following there will be some examples of functions, which I'll store in tables as given in the tutorial, for further consulting.
Unless there is a new function with non-obvious usage, there will be some examples.
- Arithmetic functions
Function Monadic form Dyadic form + Numeric Add - Negation Subtract × Sign Multiply ÷ Reciprocal Divide ⌈ Ceiling Biggest ⌊ Floor Smallest | Modulo Remainder - Algebraic functions
Functions for advanced arithmetic.
Function Monadic form Dyadic form ⍳ Index generator ? Random number Random deal ⋆ or * 'e' to the power Number to the power ⍟ Log to base 'e' Log to any base ○ π times Sine, cosine, etc ! Factorial Combinations ⌹ Matrix inversion Matrix division - Circle operator
The circle operator (
○
) does not have an obvious operation on its dyadic form. Here is a table of values of α on the case α ○ ω, taken from TryAPL:α α ○ ω α α ○ ω 0 (1-ω⋆2)⋆0.5 ¯1 Arcsin ω 1 Sin ω ¯2 Arccos ω 2 Cos ω ¯3 Arctan ω 3 Tan ω ¯4 (¯1+ω⋆2)⋆0.5 4 (1+ω⋆2)≠0.5 ¯5 Arcsinh ω 5 Sinh ω ¯6 Arccosh ω 6 Cosh ω ¯7 Arctanh ω 7 Tanh ω ¯8 -8○ω 8 (¯1+ω⋆2)⋆0.5 ¯9 ω 9 Real part of ω ¯10 +ω 10 | ω ¯11 ω × 0J1
11 Imag part of ω ¯12 ⋆ω 12 Phase of ω Also notice that
0J1
is a complex number of real part0
and imaginary part1
. - Domino operator
The Domino operator (
⌹
) generates the inverse of a matrix in its monadic form, and divides a matrix by another in its dyadic form:MAT ← 2 2⍴⍳4 ⌹MAT 5 6⌹MAT
- Circle operator
- Comparative functions
Function Monadic form Dyadic form < Less than ≤ Less than or equal = Equal ≥ Greater than or equal > Greater than ≠ Not equal ≡ Depth Match ≢ Tally Not match ∊ Enlist Membership ⍳ Iota Index of ⍷ Find Here's an interesting use for comparative functions: Suppose we have a table, where some numbers are negative. How can we test which numbers are less than zero in it?
TABLE ← 3 3⍴25-9?50 TABLE < 0
- Equal underbar
The Equal underbar (
≡
) serves two purposes. In its monadic form, it shows the depth of a specific structure.≡2 2⍴1 (2 3) (4 5 6 7) (8 (9 10) 11)
In its dyadic form, it attempts to match both parameters to see if they are equal in shape, order and values:
't' 'e' 's' 't'≡'test'
- Equal underbar slash
The Equal underbar slash (
≢
) does the exact opposite of≡
. In its monadic form, it shows the tally (shallowest depth) of a specific structure:≢2 2⍴1 (2 3) (4 5 6 7) (8 (9 10) 11)
In its dyadic form, it checks if both parameters do not match:
('t' 'e') ('s' 't')≢'test'
- Epsilon
The Epsilon (
∊
), in its dyadic form, checks whether the first parameter is enclosed in the second parameter, thus testing for membership:2∊1 2 3
The monadic form, however, enlists a certain value. If it is a scalar, it is put into a list; if it is a list, nothing changes; if it is a matrix, rows will be put one after the other to form a single list.
∊3 3 3⍴⍳27
- Epsilon underbar
The Epsilon underbar (
⍷
) is only dyadic, and attempts to find the first argument (which should be a pattern) inside the second argument. The result should be a structure which marks where the occurence starts for each occurence found.'ana' ⍷ 'banana'
- Iota
The Iota (
⍳
) in its monadic form generates a list from0
ton
.⍳9 3 3⍴⍳9
In its dyadic form, it attempts to find the second argument inside the first argument. The first match found returns the element index inside the list, matrix, etc.
X ← 0 0 5 3 X[(0≠0 0 5 3)⍳1] ⍝ Get first non-null element of X
- Equal underbar
- Logical functions
These functions work only with yielding
0
or1
by default, but they are also used for branching.All functions are dyadic, unless specified otherwise.
Function Description ~ Not (Monadic) ∨ Or ∧ And ⍱ Nor ⍲ Nand ~1 0 1 1 0 1∨0 0 1 1 0 1∧0 0 1 1 0 1⍱0 0 1 1 0 1⍲0 0 1
We can also short-circuit expressions. Should even be useful for comparisions.
(5 > 4) ∧ 1 < 3
- Manipulative functions
Function Monadic form Dyadic form ⍴ Shape Reshape , Ravel Catenate ~ Not Without ⌽ Reverse Rotate ⍉ Transpose Dyadic transpose ↑ Take first Take n
↓ Drop n
⊂ Enclose Partitioned enclose ⊃ Disclose Pick ∩ Intersection ∪ Unique Union ⊢ Identity Right ⊣ Identity Left - Comma
The Ravel (
,
) operator, in its monadic form, turns a matrix into a list.X ← 3 3 3⍴⍳27 ⍝ A cube ,X
However, we can use axis parameters to induce other behaviours.
,[1 2]X
The dyadic form catenates two structures. The particular behaviour is determined by shape.
(3 3⍴⍳9),(3 3⍴9+⍳9)
- Circle Stile
The Reverse (
⌽
), in its monadic form, reverses the elements along the last axis.⌽0 0 5 7
Its dyadic form performs a rotation on the elements of the second parameter, in the last axis, by the number of elements specified in the second parameter, as if the data were stored in a toroidal shape. Number of rotated elements' sign provides the direction.
2⌽3 3⍴⍳9 ¯2⌽3 3⍴⍳9
- Transpose
The Transpose (
⍉
), in its monadic form, reverses the axes of the given matrix.⍉3 3⍴⍳9
In its dyadic form, we can directly instruct which axes are swapped and how:
2 1 3⍉3 3 3⍴⍳27 ⍝ Swap axes 1 and 2
- Up Arrow
The Take function (
↑
), in its monadic form, gets the first element of an array.↑3 1 2
In its dyadic form, it takes exactly the number of elements specified at the first parameter, from the second parameter. If the absolute number exceeds the length, the resulting list is zero-filled. If the number is negative, it is taken from last element.
2↑⌽⍳4 ¯7↑⌽⍳4
- Down Arrow
The Drop function (
↓
) has only a dyadic form, and drops the number of elements in the first parameter from the second parameter list. If the number is negative, the drop happens from the end. If the absolute number exceeds the length, an empty response is returned. - Left Shoe
The Enclose (
⊂
) function, in its monadic form, encloses the given object into a nested scalar.⊂2 2⍴⍳4 ⍴⊂2 2⍴⍳4
In its dyadic form, it does a selective enclosing, returning the enclosed objects:
0 1 1 0⊂⍳4
- Right Shoe
The Disclose (
⊃
) function, in its monadic form, discloses the single elements of an object, zero-filling the missing elements so that all of them belong to a single shape, with the same number of dimensions.⊃(⍳4) 2 3
In its dyadic form, it recursively picks up a certain element from a nested structure.
X ← 4⍴⊂(4 4⍴16?100) ⍝ List of four enclosed 4x4 matrices 2 (2 2)⊃X ⍝ Pick 2nd matrix, then pick element [2;2]
- Right Tack
The Right (
⊢
) function does nothing in its monadic form, giving back the untouched data. Its dyadic form, however, selects the left element. It has a particularly useful property of selecting the rightmost element when mapped over a structure:2 3⊢4 5 ⊢/ 6 7 8 9
- Left Tack
The Left (
⊣
) function works much like Right, except that it selects the left element, or the leftmost element on a mapping:2 3⊣4 5 ⊣/ 6 7 8 9
- Comma
- Sorting and coding functions
Function Monadic form Dyadic form ⍋ Grade up Collated grade up ⍒ Grade down Collated grade down ⊥ Decode ⊤ Encode - Grade Up
The Grade Up (
⍋
) function, in its monadic form, returns the indexes of elements in ascending order.LIST ← 10?100 LIST[⍋LIST]
In its dyadic form, the first parameter is a collating sequence, which enumerates top-priority elements for the ordering. Elements outside of the collation are put in the end of the sequence.
TEXT ← 'Banana' TEXT['an'⍋TEXT]
- Grade Down
The Grade Down (
⍒
) function works just like Grade Up, except that it returns indexes of elements in descending order.On the dyadic form, the collating sequence enumerates elements which shall be ordered from rightmost to leftmost. Elements outside of the collation are put in the beginning of the sequence.
LIST ← 10?100 TEXT ← 'Banana' LIST[⍒LIST] TEXT['an'⍒TEXT]
- Decode
The Decode (
⊥
) function converts a number (expressed as a list) on the second argument to the base shown in the first argument.2⊥0 0 1 0 1 16⊥2 1 24 60 60⊥2 46 40 ⍝ Time conversion! 2h46m40s into total seconds
- Encode
The Encode (
⊤
) function does the opposite of Decode.2 2 2 2⊤5 7 12 24 60 60⊤10000 ⍝ Mixed radix; convert 10000 seconds to h m s
- Grade Up
- Miscellaneous functions and other symbols
Function Meaning ⎕ Numeric input from keyboard (niladic) ⍞ Character input from keyboard (niladic) ◊ Stament separator ⍝ Comment ⍎ Evaluate text as APL expression (monadic) ⍕ Format (monadic/dyadic) ⌷ Index (dyadic) ⍬ Zilde - Diamond
The statement separator (
◊
) allows for inputting more than one statement in a single line.LIST ← 25-(5?50) ◊ (÷LIST)
- Hydrant
The Execute operator (
⍎
) evaluates a textual expression as an APL statement.⍎'X ← 10×3 3⍴⍳9 ◊ ÷X'
- Thorn
The Format operator (
⍕
) in its monadic form, transforms values into a character list, suited to display onscreen.⍕1 2 3
Its dyadic form requires a format list as first argument, containing the field width for each value and its number of decimal places. The second argument is the values. If the field is not wide enough, it gives a
DOMAIN ERROR
.6 2⍕3.25 3.002 ⍝ 8 2⍕1234 ⍝ Not wide enough
- Squad
The Index operator (
⌷
) has only a dyadic form, where one can pick elements at something. It also supports axis parameters.TABLE ← 3 4⍴⍳12 2 3⌷TABLE 2⌷[1] TABLE 2⌷[2] TABLE
- Zilde
The Empty Numeric Vector (
⍬
) is a vector of zero elements.⍝ These are a match, since they are numeric vectors. ⍬≡⍳0 ⍬≡0⍴0 ⍝ These do not match. ⍬≡0 0⍴0 ⍝ Not a vector ⍬≡'' ⍝ Not numeric
- Diamond
System functions
System functions exist to extend the power of APL, improving the usable tasks.
See the implementation documentation for that.
Built-in operators
⍝ Built-in Operators
Operators are used to specify the way in which one or more functions are applied to data. For example: repeatedly, cumulatively, etc.
Operator | Name |
---|---|
/ | Slash |
⌿ | Slash bar |
\ | Backslash |
⍀ | Backslash bar |
. | Inner product |
∘. | Outer product |
¨ | Each |
[ ] | Axis |
⍨ | Duplicate/Commute |
∘ | Compose |
Reduce and scan
When used with functions as their operands, Slash and Backslash become
Reduce (/
) and Scan (\
), which apply a single function to all elements
of an argument.
⍝ These two operations are equivalent 22 + 93 + 4.6 + 10 + 3.3 +/22 93 4.6 10 3.3 ⍝ Reduce using plus
In the last example, Reduce interposes the +
between the values on the
vector. Were it replaced by the Scan operator, the same would happen,
but the result would be a vector containing intermediate results; the
last element of such vector would be the last result.
+\22 93 4.6 10 3.3 ⍝ Scan using plus 22 (22+93) (115+4.6) (119.6+10) (129.6+3.3) ⍝ Equivalent calculation
- Reduce First and Scan First
Using a Slash bar with a function means using the Reduce First (
⌿
) operator. This will apply a reduction on the first dimension of the data structure:TABLE ← 3 5⍴15?30 +⌿ TABLE
Using a Backslash bar with a function means using the Scan First (
⍀
) operator. This does something similar to Scan, but stores each result in a matrix row (first dimension).+⍀ TABLE
Compress and expand
When used with one or more numbers, Slash and Backslash become
Compression (/
) and Expansion (\
).
Compress selects a part of an object:
1 0 1 1 0 1 / 'ABCDEF'
Expand inserts fill data into objects:
TABLE ← 2 3⍴⍳6 ⍝ Insert new columns (axis 2). ⍝ New columns indicated by zeroes. 1 0 1 0 1\[2]TABLE
- Compress First and Expand First
The Compress First (
⌿
) operator, also known as Replicate First, is the dyadic form of the Slash Bar, and can be used in a matrix to remove and duplicate certain rows (first dimension):TABLE ← 3 4⍴⍳12 1 0 2⌿TABLE ⍝ Remove 2nd row, duplicate 3rd row
The Expand First (
⍀
) operator is the dyadic version of the Backslash bar, and also works by adding new rows (first dimension) to a matrix.TABLE ← 3 4⍴⍳12 1 0 1 0 1 0 0⍀TABLE
Outer and inner products
Product operators distribute the application of a function between each element of one argument and all elements in another; this removes the constraint on applying certain functions to arguments of same shape.
- Outer Product
The outer product (
∘.
)gives the result of applying the function to all combinations of elements in both arguments:1 2 3∘.+4 5 6
The result is a 3×3 matrix, where the first column is the sum between
1
and each of the numbers in the second argument; the second column is the sum between2
and each of the numbers in the second argument; and so on.Another example: a matrix of powers.
(⍳4)∘.*⍳4
- Inner Product
The inner product (
.
) allows two functions to be applied to arguments; operations happen between the last dimension of the left argument, and the first dimension of the right argument; so the two inner dimensions are used.Using this on matrices results in two steps:
- Each row of the left argument is applied to each column of the right argument. This uses the rightmost function;
- The leftmost function is applied to the result, through a Reduction
(
/
).
X←3 3⍴9?100 Y←3 3⍴9?100 ⍝ 1. Each row of X is multiplied by each column of Y; ⍝ 2. The result is reduced through a sum. X+.×Y
There are up to 400 possible inner products. Some uses are:
- Locating incidences of given character strings within textual data;
- Evaluation of polynomials;
- Matrix multiplication;
- Product of powers;
- Etc.
Each
The Each operator (¨
) allows applying a certain function (on the left)
to each elements of an array or vector (on the right).
⍴¨(⍳3)(⍳2)(⍳5) ⍝ Find the length of each vector
Axis
Some functions operate in data which has more than one dimension. One can change the axis in which they operate by using the axis operator.
By default, APL functions work on the last dimension of your data. The
order of dimensions is the one show when you apply ⍴
to the data.
TABLE ← 2 3⍴⍳6 ⍝ A matrix of 2×3 (two dimensions) ⍝ Reduce with + on the second dimension. This gives a ⍝ list of two numbers, each being the sum of numbers ⍝ along the COLUMNS (dimension 2, last one) of each ⍝ row of the matrix. +/TABLE ⍝ This reduction specifies that the sum should occur ⍝ along the ROWS (dimension 1) of a column of the ⍝ matrix, therefore it gives a list of three numbers. +/[1]TABLE
- Functions that accept axis specifications
here are some built-in functions and operators that accept specifying axes:
- Functions
↑
(First, Take)↓
(Drop)⊂
(Enclose, Partition)⊃
(Disclose, Pick),
(Ravel, Catenate)⌽
,⊖
(Reversal, Rotation)
- Operators
/
(Reduce, Compress)\
(Scan, Expand)⌿
(Reduce First, Compress First)⍀
(Scan First, Compress First)
- Functions
User-defined Functions
⍝ User-defined functions
Arguments and results
Functions can be thought of as external programs which are run. They can be:
- Niladic: They have no specified arguments.
- Monadic: Functions have one argument, passed at its right.
- Dyadic: Functions have two arguments, the first is passed at its left and the second is passed at its right.
Passing many values as an argument is enclosed into a single vector of arguments.
Definining a function that is both monadic and dyadic require testing the first and second arguments to dispatch based on it.
If you need to express a result, you will also need to give a name for the result field.
User-defined operators
Operators must have one or two operands, which are functions; not more nor less, since operators are used to modify the behaviour of functions.
Editing functions
Some APLs allow you to edit a function by using the )EDIT
command or
the ⎕EDIT
system function. This is the case for Dyalog, for example –
however, Dyalog uses the )ED
command instead.
)ED FUNK
Older APL systems, like GNU APL, allows editing one-line-at-time,
using the Del (∇
) editor. However, the gnu-apl-mode
for Emacs replaces
the use of Del by opening a new temporary buffer to edit the function.
∇FUNK
APL uses the concept of workspaces to store functions and values,
however one can safely use the Del (∇
) notation to define a certain
function in an APL code file:
∇FUNK ⍝ Add some code here... ∇
The rest of this text will use the Del editor notation, in a way which it can be executed in a GNU APL script, therefore some things will be different e.g. line numbers will not be used here.
The function header
When typing the function, one must type a suitable function header, for example:
∇SD X SUM ← +/X AVG ← SUM÷⍴X DIFF ← AVG-X SQDIFF ← DIFF⋆2 SQAVG ← (+/SQDIFF)÷⍴SQDIFF RESULT ← SQAVG⋆0.5 ∇
This function takes a vector called X
and performs some computation
using it.
SD 12 45 20 68 92 108
The result exists in the global variable RESULT
, created inside the
function.
If we were defining a function with two operators, we would have a header such as:
∇X CALC Y
And if we wanted the result to be put in a specific variable, see how
we could redefine SD
:
∇R ← SD X SUM ← +/X AVG ← SUM÷⍴X DIFF ← AVG-X SQDIFF ← DIFF⋆2 SQAVG ← (+/SQDIFF)÷⍴SQDIFF R ← SQAVG⋆0.5 ∇
By doing this, the result of applying SD
to something could be
assigned to a variable; R
itself is not a variable which is visible
outside of SD
, acting as a surrogate for the final result of
execution.
The operator header
Operator bodies are defined just like functions'; what changes is the header, which must specify an operator.
Here is the header of a monadic operator:
∇R ← X (LOP OPERATE) Y
And the header of a dyadic operator:
∇R ← X (LOP OPERATE ROP) Y
OPERATE
is the operator name;R
is the optional return variable;X
andY
are left and right parameters for the operator;LOP
is an obligatory left operand, which the operator will change the behaviour of;ROP
is an optional right operand, which the operator will also change the behaviour of.
Local and global variables
One can quote variables in the header to make sure they are local to the function; by not doing so, they will remain global. Also notice that local variables are not shared with variables called inside the function body.
So let's fix SD
.
)CLEAR ⍝ Clear the workspace ∇R ← SD X;SUM;AVG;DIFF;SQDIFF;SQAVG SUM ← +/X AVG ← SUM÷⍴X DIFF ← AVG-X SQDIFF ← DIFF⋆2 SQAVG ← (+/SQDIFF)÷⍴SQDIFF R ← SQAVG⋆0.5 ∇
But the header is so big, that's not good. Let's try making this a little more compact so we have fewer local variables.
∇R ← SD X;SQDIFF SQDIFF ← (X-(+/X)÷⍴X)⋆2 R ← ((+/SQDIFF)÷⍴SQDIFF)⋆0.5 ∇
Branching
Inside the body of a function or operator, the symbol Goto (→)
is used
to determine a jump. The symbol should then be followed by some data;
if the data is a scalar, the function jumps to the given line. If it
is a vector, the function jumps to the first element of the vector and
ignores the rest of it.
Here is an example of that in action, with numbering on the body for better understanding.
∇R←TEST X [1] →(X≥0)/4 [2] R←0 [3] →5 [4] R←1 ∇
The function starts by testing whether X
is greater or equal to
zero. If so, the result is 1
, therefore the Compress (/
) operator
selects the sole number at the right, which is 4
. The →
symbol then
instructs the function to jump to the line – that is, the fourth one.
Line [2]
puts a 0
on the result variable. Then line [3]
instructs the
program to make an unconditional jump to the line 5
, which does not
exist – thus ending the function.
Line [4]
attributes the number 1
to the result variable, and then
exits gracefully, as there are no more jumps.
- Looping
One can also perform loops very easily by using the Goto symbol (
→
). For example, consider the following function.⍝ Calculate factorial of a scalar N. ⍝ Has a return variable and a local scalar I. ∇R←FACTORIAL N;I →(N≤0)/0 ⍝ 1: If N is lower or eq to 0, end function I←1 ⍝ 2: Initialize iterator to 1 R←1 ⍝ 3: Initialize result to 1 R←R×I ⍝ 4: Let result be the mult. of result and iter →(I=N)/0 ⍝ 5: If iterator is equal to N, end function I←I+1 ⍝ 6: Increment iterator →4 ⍝ 7: Jump to multiplication ∇
Jumping to
0
will be explained below; it ends the function. - Labels
It is not necessary to count lines on most modern APLs. We can just use labels. This is also useful when adding lines and whatnot.
∇R ← TEST X →(X≥0)/GREATEQ R←0 →0 GREATEQ: R←1 ∇
Here is the factorial function, rewritten using labels:
∇R←FACTORIAL N;I →(N≤0)/0 (I R)←1 ⍝ Multiple definition at once LOOP: R←R×I →(I=N)/0 I←I+1 →LOOP ∇
- Ending execution of a function
A function stops naturally when the last line of its body is executed. However, one can go to a line number which doesn't exist to end the function immediately. For example:
→(X<1)/0 →0 →7 ⍝ Suppose this line is in a function with six lines
- Structured control keywords
Some APLs support structured-control keywords for flow control. This makes APL more readable. (GNU APL, however, does not support them)
Here is a table of keywords. These keywords are not part of the APL ISO, but they are supported in many implementations.
Function Keyword Conditional execution :If
,:ElseIf
,:Else
,:EndIf
For loop :For
,:EndFor
While loop :While
,:EndWhile
Repeat loop :Repeat
,:EndRepeat
Case selection :Select
,:Case
,:CaseList
,:Else
,:EndSelect
Branch :GoTo
Terminate function :Return
(same as→0
) - Comments in functions
Just use the Lamp (
⍝
) symbol. - Ambivalent Functions
In APL2, dyadic functions may be used monodically. This happens when the left argument is undefined. This means that its Name Classification (
⎕NC
) is0
. This can be compared:∇R←A AMBIVALENT B →(0=⎕NC 'A')/MONADIC →DYADIC MONADIC: A←5 DYADIC: R←A+B ∇ 1 AMBIVALENT 2 ⍝ Dyadic usage; yields 3 AMBIVALENT 2 ⍝ Monadic usage; yields 7
Some APLs like NARS2000 and Dyalog use a particular syntax which distinguishes ambivalent and dyadic functions. See these function headers:
∇R←A NOMADIC B ⍝ Dyadic ∇ ∇R←{A} NOMADIB B ⍝ Ambivalent ∇
Extra: Lambdas
GNU APL has limited support for lambda expressions. Those are functions which are defined inline, and can even be named.
In lambdas, Alpha (⍺
) is the symbol used for the left argument, and
Omega (⍵
) is the symbol used for the right argument. All lambdas are
one-line functions, enclosed in Curly Brackets ({}
), which can be
monadic or dyadic depending on argument usage, and their single line
always return a value.
AVERAGE ← {(+/⍵)÷⍴⍵} ⍝ Named lambda 2 {⍺+⍵} 3 ⍝ Unnamed lambda, applied immediately
Here is an example lambda function which finds all the prime numbers
below the second argument (⍵
) of the monadic function (ACHARYA and
PEREIRA):
PRIMES ← {(~⍵∊⍵∘.×⍵)/⍵←1↓⍳⍵} PRIMES 100
Error Handling
⍝ Error handling
Errors in calculator mode
APL prints errors when you type a statement containing an error in
calculator mode. For example, this yields a DOMAIN ERROR
:
1 1 0 'a'∨1 1 0 0
To correct an error in calculator mode, simply retype the statement correctly, or use the the implementation's line-editing facilities.
Errors in user-defined functions or operators
When executing a user-defined function or operator, if an error happens, the execution stops at that point. Modern APLs have a Debug window where you can examine and correct errors in the function or operator.
The state indicator
When the halted function was called by other function, one can inspect
the call stack using the State Indicator. This can be done with the
system function )SI
or, in some APLs, by inspecting the variable ⎕SI
.
Here is an example taken from implementation APLX (deprecated):
)SI C[2] * B[8] A[5]
In the example above, the problem happened at function C
, at line
2
. This function was called by function B
at line 8
, which was then
called by function A
on line 5
.
The asterisk means that the execution of line 2
of function C
is still
pending. If another function were executed at this point and also
yielded an error, this would happen:
E[3] * D[6] C[2] * B[8] A[5]
So now function E
at line 3
is pendent, and was called from function D
at line 6
.
This top level can be cleared by using the Goto symbol (→
). Another
→
, in this case, would clear the State Indicator completely.
→ )SI C[2] * B[8] A[5]
There are also system functions to clear the State Indicator. In GNU
APL, this can be done with )RESET
.
Action after suspended execution
One can resume the suspended execution where it stopped. To do so,
just type Goto (→
) followed by the line number.
→3 ⍝ Suppose execution halted at line 3 of the function
It is not mandatory to continue execution where the function halted. For example, suppose you want to restart at the next line:
→4
Another way to do this is by using the niladic system function
⎕LC
. This yields a vector containing all current line numbers of
functions in the State Indicator. All we need to do is to jump to the
first number of such vector:
→⌷LC
Or, if we want to resume at the next line, we can also exploit the vector:
→1+⎕LC
Error trapping and tracing
It is possible to specify in advance what to do if an error occurs on execution; APL allows error trapping at runtime.
- Dyalog has the keywords
:Trap
,:EndTrap
,:Case
and:Else
, and the system variable⎕TRAP
which allows precise control; - APL2 has the system variables
⎕EA
(Execute Alternate; executes the right argument and, if it fails, executes the left one) and⌷EC
(Execute Controlled; Executes the argument and returns the result, if any. Also returns additional information on errors). - APL+Win has the keywords
:Try
,:Catch
and:Finally
; and the⎕ELX
system variable executes the argument passed on its right, whenever an error occurs. - NARS2000 has
⎕ELX
like APL+Win, and⎕EA
and⌷EC
, like APL2.
It seems like GNU APL does not have error trapping facilities.
Formatting
⍝ Formatting
The "Format" primitive
Useful variable: ⎕PP
(Print Precision).
When the left argument is not specified, the data is converted into plain text with no specific format, using only display defaults.
⍕ 0.0000003 3.0123456789
With two arguments, the left argument is always a list of two elements: Field width and number of decimal places.
6 2⍕341.82921
Note that, before the number was truncated, it was rounded.
The system function ⎕FMT
Some APL implementations (except APL2 and GNU APL) have a ⎕FMT
system
function:
'B K2 G< ZZ9 DOLLARS AND 99 CENTS>' ⎕FMT 8.23 12.86 0 2.52 8 DOLLARS AND 23 CENTS 12 DOLLARS AND 86 CENTS 2 DOLLARS AND 52 CENTS
End of Tutorial
)CLEAR
Further Topics in APL
These are very useful topics which I will only take some notes on new things I find interesting. Here is the link to the relevant contents.
It is also useful to check the GNU APL Manual
Displaying the Shape of an Array
⍝⍝⍝ Further Topics in APL ⍝ Displaying the shape of an array
Most APLS have a DISPLAY
or ⎕DISPLAY
system function to draw boxes
around data. GNU APL uses ⎕CR
for that. For example:
8⎕CR 3 4⍴12?50 8⎕CR 1 (⍳2) 3 4 5 8⎕CR 1 'A' (2 3) (2 5⍴'HELLOWORLD')
Results are better seen with GNU FreeFont:
┌→──────────┐ ↓40 26 30 24│ │50 35 31 47│ │43 45 38 11│ └───────────┘ ┌→────────────┐ │1 ┌→──┐ 3 4 5│ │ │1 2│ │ │ └───┘ │ └∊────────────┘ ┌→────────────────┐ │1 A ┌→──┐ ┌→────┐│ │ │2 3│ ↓HELLO││ │ └───┘ │WORLD││ │ └─────┘│ └∊────────────────┘
Meaning of symbols used when drawing boxes:
Sym | Placement | Meaning |
---|---|---|
- | Beneath character | Scalar character |
→ | Left of top edge | Vector or higher-rank array |
~ | Left of bottom edge | Numeric data |
+ | Left of bottom edge | Mixed data |
⊖ | Left of top edge | Empty vector or higher-rank array |
↓ | Left side of box | Matrix or higher-rank array |
⌽ | Left side of box | Empty matrix or higher-rank array |
∊ | Left of bottom edge | Nested array |
Array Type and Prototype
⍝ Array type and prototype
Arrays of one or more dimensions of zero length are known as empty
array, which can be generated with Reshape (⍴
) or a selection of sorts
(like with Compress, /
). Its type can be numeric, simple character or
nested, depending on how it was created.
Empty arrays are useful for initializing arrays where data will be
added in the future, for creating scalars from arrays or as argument
to Goto (→
).
Array Type and Prototype
Arrays have a type zero for numeric elements, and blank character for character elements.
⍝ Empty numeric vector and empty character vector 8⎕CR ⍳0 ◊ 8⎕CR '' ⍝ Same thing, but using ⍴ 8⎕CR 0⍴676 ◊ 8⎕CR 0⍴'PETER'
┌⊖┐ │0│ └─┘ ┌⊖┐ │ │ └─┘
Empty numeric vectors can also be created using Zilde (⍬
).
X←⍬ ⍴X X≡0⍴0 8⎕CR ⍬
0 1 ┌⊖┐ │0│ └─┘
Prototypes of nested arrays
Complex empty arrays can be created by using a nested array to generate the empty array:
⍝ A nested array containing a list of characters ⍝ and a list of numbers; the second statement ⍝ is an empty nested array containing another ⍝ empty array. 8⎕CR 'ABC' (⍳3) ◊ 8⎕CR 0⍴'ABC' (⍳3)
┌→────────────┐ │┌→──┐ ┌→────┐│ ││ABC│ │1 2 3││ │└───┘ └─────┘│ └∊────────────┘ ┌⊖────┐ │┌→──┐│ ││ ││ │└───┘│ └∊────┘
When the first element is numeric, we end up with a nested array of null elements.
8⎕CR (2 2⍴⍳4) 'ABC' ◊ 8⎕CR 0⍴(2 2⍴⍳4) 'ABC'
┌→──────────┐ │┌→──┐ ┌→──┐│ │↓1 2│ │ABC││ ││3 4│ └───┘│ │└───┘ │ └∊──────────┘ ┌⊖────┐ │┌→──┐│ │↓0 0││ ││0 0││ │└───┘│ └∊────┘
If the first element is mixed, then we'll have an array filled with zeroes and empty characters.
8⎕CR (2 2⍴1 'K' 2 'J') (⍳4) ◊ 8⎕CR 0⍴(2 2⍴1 'K' 2 'J') (⍳4)
┌→──────────────┐ │┌→──┐ ┌→──────┐│ │↓1 K│ │1 2 3 4││ ││2 J│ └───────┘│ │└───┘ │ └∊──────────────┘ ┌⊖────┐ │┌→──┐│ │↓0 ││ ││0 ││ │└───┘│ └∊────┘
Therefore, the prototype concept can be used to display the type of an array.
8⎕CR VAR ← (2 2⍴1 'A' 'B' 2) ((⍳2) 7) 'ABC'
┌→────────────────────┐ │┌→──┐ ┌→──────┐ ┌→──┐│ │↓1 A│ │┌→──┐ 7│ │ABC││ ││B 2│ ││1 2│ │ └───┘│ │└───┘ │└───┘ │ │ │ └∊──────┘ │ └∊∊───────────────────┘
To display the array type, we first enclose (⊂
) the array to make it a
scalar, then we build the empty vector with it (0⍴
). Since building
the empty vector creates an additional level of nesting, we use the
First (↑
) function to remove it:
8⎕CR ↑0⍴⊂VAR
┌→────────────────────┐ │┌→──┐ ┌→──────┐ ┌→──┐│ │↓0 │ │┌→──┐ 0│ │ ││ ││ 0│ ││0 0│ │ └───┘│ │└───┘ │└───┘ │ │ │ └∊──────┘ │ └∊∊───────────────────┘
The prototype as a fill element
Functions such as Take (↑
), Expand (\
) and Replicate (/
) add elements
to an existing array. A prototype can be used to determine the type
and shape of extra elements.
Type of array | Fill Element |
---|---|
Numeric | 0 |
Character | Space |
Nested/Mixed | Prototype of first element, with |
Numbers/Characters replaced | |
accordingly |
Here are some examples.
8⎕CR 5↑1 2 3 ◊ 8⎕CR 5↑'ABC' ⍝ Numeric and textual vectors of 5 elts 8⎕CR 2↑0⍴⊂VAR ⍝ Vector containing two prototypes 8⎕CR 2↑⊂VAR ⍝ Put VAR's prototype after VAR, in a vector 8⎕CR ¯2↑⊂VAR ⍝ Put VAR's prototype before VAR, in a vector
┌→────────┐ │1 2 3 0 0│ └─────────┘ ┌→────┐ │ABC │ └─────┘ ┌→──────────────────────────────────────────────┐ │┌→────────────────────┐ ┌→────────────────────┐│ ││┌→──┐ ┌→──────┐ ┌→──┐│ │┌→──┐ ┌→──────┐ ┌→──┐││ ││↓0 │ │┌→──┐ 0│ │ ││ │↓0 │ │┌→──┐ 0│ │ │││ │││ 0│ ││0 0│ │ └───┘│ ││ 0│ ││0 0│ │ └───┘││ ││└───┘ │└───┘ │ │ │└───┘ │└───┘ │ ││ ││ └∊──────┘ │ │ └∊──────┘ ││ │└∊∊───────────────────┘ └∊∊───────────────────┘│ └∊∊∊────────────────────────────────────────────┘ ┌→──────────────────────────────────────────────┐ │┌→────────────────────┐ ┌→────────────────────┐│ ││┌→──┐ ┌→──────┐ ┌→──┐│ │┌→──┐ ┌→──────┐ ┌→──┐││ ││↓1 A│ │┌→──┐ 7│ │ABC││ │↓0 │ │┌→──┐ 0│ │ │││ │││B 2│ ││1 2│ │ └───┘│ ││ 0│ ││0 0│ │ └───┘││ ││└───┘ │└───┘ │ │ │└───┘ │└───┘ │ ││ ││ └∊──────┘ │ │ └∊──────┘ ││ │└∊∊───────────────────┘ └∊∊───────────────────┘│ └∊∊∊────────────────────────────────────────────┘ ┌→──────────────────────────────────────────────┐ │┌→────────────────────┐ ┌→────────────────────┐│ ││┌→──┐ ┌→──────┐ ┌→──┐│ │┌→──┐ ┌→──────┐ ┌→──┐││ ││↓0 │ │┌→──┐ 0│ │ ││ │↓1 A│ │┌→──┐ 7│ │ABC│││ │││ 0│ ││0 0│ │ └───┘│ ││B 2│ ││1 2│ │ └───┘││ ││└───┘ │└───┘ │ │ │└───┘ │└───┘ │ ││ ││ └∊──────┘ │ │ └∊──────┘ ││ │└∊∊───────────────────┘ └∊∊───────────────────┘│ └∊∊∊────────────────────────────────────────────┘
More info: Empty Arrays and Prototypes
Vector Notation
Nothing new here. Just pay attention to how the vectors are constructed:
8⎕CR 'ABC' 'DEF' 8⎕CR (1 2 3) 'DEF' ⍴1 2 3 'DEF' ⍴1 2 3 'D' 'E' 'F' 8⎕CR ((1 2) (3 4)) 2 3 X←2 2⍴⍳4 Y←'HELLO' 8⎕CR (X Y) ⍝ Variables entered in vector form ⍴X Y
8⎕CR 'ABC' 'DEF' ┌→──────────┐ │┌→──┐ ┌→──┐│ ││ABC│ │DEF││ │└───┘ └───┘│ └∊──────────┘ 8⎕CR ((1 2 3) 'DEF') ┌→────────────┐ │┌→────┐ ┌→──┐│ ││1 2 3│ │DEF││ │└─────┘ └───┘│ └∊────────────┘ ⍴1 2 3 'DEF' 4 ⍴1 2 3 'D' 'E' 'F' 6 8⎕CR ((1 2) (3 4)) 2 3 ┌→────────────────┐ │┌→──────────┐ 2 3│ ││┌→──┐ ┌→──┐│ │ │││1 2│ │3 4││ │ ││└───┘ └───┘│ │ │└∊──────────┘ │ └∊∊───────────────┘ X←2 2⍴⍳4 Y←'HELLO' 8⎕CR (X Y) ⍝ Variables entered in vector form ┌→────────────┐ │┌→──┐ ┌→────┐│ │↓1 2│ │HELLO││ ││3 4│ └─────┘│ │└───┘ │ └∊────────────┘ ⍴X Y 2
Variables and Indexing
Nothing new too.
LIST←12 24 36 48 LIST[2] LIST[1]+LIST[4] ALF←'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ALF[26 1 13 2 9 1] TABLE←10×2 4⍴⍳8 TABLE[1;4] TABLE[1;⍳4]+TABLE[2;⍳4] TABLE[1;]+TABLE[2;] (⍴TABLE[1;2 3])=(⍴1),⍴2 3 ALF[2 2⍴⍳4] ⍴TABLE[1;] ⍝ Rows indexed by scalar, result is vector ⍴TABLE[,1;] ⍝ Rows indexed by vector, result is matrix ⍴TABLE[1 1⍴1;] ⍝ Rows indexed by matrix, result is cube
The Index (⌷
) function
TABLE[1;2]=1 2⌷TABLE 2⌷⍳5 (⊂3 4)⌷⍳5 ⍝ Use a nested scalar for multiple index. TAB←2 5⍴⍳10 8⎕CR TAB 2 3⌷TAB 2 (2 3)⌷TAB ⍝ 2nd element of indexing vec is an enclosed vec ⍝ Nested 2-elts vector for multiple indexes. ⍝ Result is a submatrix of TAB located at ⍝ rows 1 2, columns 2 3. (1 2) (2 3)⌷TAB ⍝ An empty left argument is OK for index when ⍝ a scalar is the right argument. This returns ⍝ the scalar itself. (⍳0)⌷37
Multiple Specification
Nothing new here as well.
(A B C)←1 2 3 A ◊ B ◊ C (A B C)←5 A ◊ B ◊ C (A B C)←'HI' 'THERE' 'FOLKS' ⍴A ⍝ See that A received 'HI' only (A B C)←⊂'HI' 'THERE' 'FOLKS' ⍴A ⍝ All three variables received a vec of the three char vecs 8⎕CR A
Selective Specification
Some functions in APL can be used to select portions of an array. When associated with assignment, they can be used to assign values to portions of such array.
Bracket indexing is the easiest example.
TAB←2 3⍴⍳6 TAB[2;1]←8
Let's assign the first three elements of a vector by using the Take
(dyadic ↑
) function.
VEC←⍳5 (3↑VEC)←'ABC' 8⎕CR VEC
┌→──────┐ │ABC 4 5│ └───────┘
Let's use the Ravel (monadic ,
) on a matrix to assign a new vector
value to it:
MAT←3 4⍴'ABCDEFGHIJKL' (,MAT)←'NEW DATAHERE' ⍝ Ravelled matrix appears as a vector 8⎕CR MAT ⍝ Assignment occurs in matrix itself
┌→───┐ ↓NEW │ │DATA│ │HERE│ └────┘
Now let's combine Compression (dyadic /
) and Ravel (monadic ,
) to
select all A's on the matrix, and replace them by asterisk:
(('A'=,MAT)/,MAT)←'*' 8⎕CR MAT
┌→───┐ ↓NEW │ │D*T*│ │HERE│ └────┘
We can also combine Take (dyadic ↑
) and Ravel (monadic ,
) to replace
elements at the top-left 2×2 submatrix of MAT
:
(,2 2↑MAT)←'⎕⎕⎕⎕' 8⎕CR MAT
┌→───┐ ↓⎕⎕W │ │⎕⎕T*│ │HERE│ └────┘
We can also use the Compression (/
) function for selection.
TABLE←3 4⍴⍳12 8⎕CR TABLE (1 0 1 0/TABLE)←3 2⍴100 8⎕CR TABLE
┌→─────────┐ ↓1 2 3 4│ │5 6 7 8│ │9 10 11 12│ └──────────┘ ┌→────────────┐ ↓100 2 100 4│ │100 6 100 8│ │100 10 100 12│ └─────────────┘
In the next example, we have a vector X
. We want to replace the first
⍴X
elements of DATA
with the contents of X
.
DATA←⍳13 X←10×⍳3 8⎕CR DATA ((⍴X)↑DATA)←X 8⎕CR DATA
┌→────────────────────────────┐ │1 2 3 4 5 6 7 8 9 10 11 12 13│ └─────────────────────────────┘ ┌→───────────────────────────────┐ │10 20 30 4 5 6 7 8 9 10 11 12 13│ └────────────────────────────────┘
Replace the first X+2
elements of Y
with the reverse of a vector
containing numbers 1
up to X+2:
Y←⍳10 X←3 8⎕CR Y ((2+X)↑Y)←⌽⍳X+2 8⎕CR Y
┌→───────────────────┐ │1 2 3 4 5 6 7 8 9 10│ └────────────────────┘ ┌→───────────────────┐ │5 4 3 2 1 6 7 8 9 10│ └────────────────────┘
We can use Enlist (monadic ∊
) to remove nesting from an array.
8⎕CR NEST←(2 2⍴⍳4) 'TEXT' (3 1⍴⍳3) (∊NEST)←0 8⎕CR NEST ⍝ Set specific position to number (6⌷∊NEST)←999 8⎕CR NEST ⍝ Set specific position to character vector (text). ⍝ For that, introduce extra nesting to the new text. (7⌷∊NEST)←⊂'TEXT' 8⎕CR NEST
┌→───────────────┐ │┌→──┐ ┌→───┐ ┌→┐│ │↓1 2│ │TEXT│ ↓1││ ││3 4│ └────┘ │2││ │└───┘ │3││ │ └─┘│ └∊───────────────┘ ┌→──────────────────┐ │┌→──┐ ┌→──────┐ ┌→┐│ │↓0 0│ │0 0 0 0│ ↓0││ ││0 0│ └───────┘ │0││ │└───┘ │0││ │ └─┘│ └∊──────────────────┘ ┌→────────────────────┐ │┌→──┐ ┌→────────┐ ┌→┐│ │↓0 0│ │0 999 0 0│ ↓0││ ││0 0│ └─────────┘ │0││ │└───┘ │0││ │ └─┘│ └∊────────────────────┘ ┌→─────────────────────────┐ │┌→──┐ ┌→─────────────┐ ┌→┐│ │↓0 0│ │0 999 ┌→───┐ 0│ ↓0││ ││0 0│ │ │TEXT│ │ │0││ │└───┘ │ └────┘ │ │0││ │ └∊─────────────┘ └─┘│ └∊∊────────────────────────┘
The function First (monadic ↑
) selects the first element of an
array. Here, we shall replace the first 2×2 matrix of NEST
by a
character vector.
(↑NEST)←'ABC' 8⎕CR NEST
So, the sky is the limit. For more info, see this page.
Binding Strengths
In general, APL evaluates from right to left. However, some elements can be said to have stronger binding.
Here is a descending list of binding strength.
Binding | Bound items |
---|---|
Brackets [] |
Brackets to object to the left |
Specification ← left |
← to object on its left |
Right operand | Dyadic operator to its right operand |
Vector | Array to array |
Left operand | Operator to its left operand |
Left argument | Function to left argument |
Right argument | Function to right argument |
Specification ← right |
← to object on its right |
And parentheses can override the binding strength hierarchy.
For more info, see this page.
Pervasive Functions
There are Scalar and Mixed functions in APL. Scalar functions have the property of being pervasive, that is, they apply to all levels of nesting on the data.
Here are some scalar functions:
+ - × ÷ | ⌈ ⌊ * ⍟ ○ ! ^ ∨ ⍲ ⍱ < ≤ = ≥ > ≠ Monadic ~ Monadic ?
For more info, see this page.
OO, Classes and Inheritance
GNU APL does not support object orientation, therefore I will not be covering it. However, Dyalog APL does.
Object-oriented APL information can be found on this page.
Finishing
⍝ Closes the script file. )OFF