Practical Uses of a Model of APL

Kenneth E. Iverson
I.P. Sharp Associates
Toronto, Ontario, Canada

Arthur T. Whitney
Edmonton, Alberta, Canada



Abstract

This paper discusses the use of a general model of APL (written in APL) which allows convenient definition of new operators and functions and experimentation with their use. Use of the model is illustrated by a number of functions and operators, some of which have been previously discussed, and some (such as the operator til) which are new. Details of the model itself are not treated.
 

Introduction

The effective use of new facilities introduced into APL systems is often long delayed, not only because of a programmer’s tendency to cling to familiar ways, but also because the abstract, formal treatment necessary to the specification of a new facility often makes its assimilation and use seem unduly difficult. Working models of new facilities available before their actual introduction can be very helpful in teaching, their use, and very effective in speeding their widespread application.

However, the development of an accurate model for each new facility can, especially in the case of new operators, be burdensome, and we have found that a general model of the APL interpreter, developed primarily for use by the language designers in the design and modelling of new extensions, can also be useful in providing specific models for the enlightenment of users.

This paper discusses such uses of the general model, employing illustrations executed by the version available on the I.P. Sharp Associates APL system. Except for information necessary for understanding its use, details of the model will not be discussed here.

The model incorporates a number of facilities proposed in earlier papers [1 2 3]; the more fundamental among them are illustrated below. The model, invoked by executing the function ∆APL , accepts character input and parses and executes the expression entered. 0-origin indexing is used throughout the paper.

   ∆APL
   a←1 2 3    
   mp←+.×     
   dot←.

   a mp a
14
   a + dot × a
14

may be used to assign names to functions and operators as well as to variables [1 3]

   cf←'⍺+÷⍵' ∇ '⍵∆⍵'

   a cf a
2 2.5 3.33333333
   cf a
2 2.5 3.33333333

The function definition operator may be used to define ambivalent functions [3]

   cf/a
1.42857143
   cf\a
1 1.5 1.42857143
   +.×⌿ 3 2 2⍴⍳12
118 131
518 575

Operators apply to defined and derived functions as well as to primitives

   q←×∇-
   a q a
1 4 9
   q a
¯1 ¯2 ¯3
   r←*∇'10*⍵'
   3 r a
3 9 27
   r 1
10 100 1000

The operatorapplies to functions as well as to character vectors

   ⊣←'⍺'∇''

An assignment can be made to a graphic name (is now the function lev which returns its left argument)


   c1←2 2⍴'bare'⊣c2←2 2⍴'bear'

   c1
ba
re
   c2
be
ar
   ←+.×

   a  a
14

New composite symbols can be used

Assignment of values to graphic symbols is, of course, intended for use in language design, and is not proposed for general inclusion in the language. It is, nevertheless, convenient for use in experimentation by programmers as well as by language designers.

The use of new composite symbols is possible because the model receives and handles arbitrary input (⎕arbin in IPSA APL), that is, all terminal inputs including backspace and attention are transmitted directly to it. The model also incorporates a definition from [1] which illustrates the notion that an operator may produce an ambivalent derived function — specifically, the monadic derived function produced by reduction is supplemented by a dyadic case in which the left argument specifies the width of the “window” over which reduction is applied. For example:

   p←13 11 7 5 3 2
   2 -/ p
2 4 2 2 1
Pairwise differences
   (4+/p)÷4
9 6.5 4.25
Running Averages
   ^/2 ≥/p
1

 
Test for decreasing sequence

A. Some New Functions

We will further illustrate the use of the model in simple cases by defining a few functions (most of which have been defined in earlier papers [1 2]) for use in later examples:

   ∩←'(l∊⍵)/l←,⍺' ∇ ''
Set intersection
   ~←'(~l∊⍵)/l←,⍺' ∇ ~

   'abacus' ∩ 'scab'
abacs

   'abacus' ~ 'scab'
u

Set difference. Note that the monadic definition of ~ is preserved.

   ∪←'' ∇ '((⍳⍴⍵)=⍵⍳⍵)/⍵←,⍵'
 

Nub (set of distinct elements)
 

   ∪ 'abacus'
abcus

   ←'' ∇ '(∪⍵)∘.=⍵'

    'abacus'
1 0 1 0 0 0
0 1 0 0 0 0
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
Distribution [1]
    ⍳3
1 0 0
0 1 0
0 0 1

applied to any vector of distinct elements produces an identity matrix

   ⎕←w←r⊥⍳⍴r←8 4 5 2
40 10 2 1

   +/w×1 2 3 4
70
   r⊥1 2 3 4
70

The weights associated with the radix r

B. Enclosed Arrays

Enclosed arrays provide a good example of a notion whose formal treatment makes it seem unduly difficult. For example, a graphic display of enclosed arrays is very helpful to the beginner, but the definition of a suitable display is recursive and somewhat complicated. However, its behaviour is immediately evident from a model. The definition of display, (i.e., of the function) used here, is a modification (due largely to P.K. Wooster) of the definition in [2], and may be illustrated as follows:

   ⎕ps←0 0 ¯3 ¯3

   ⎕←q←2 2⍴(<a),(<(<c1),<c2),<a∘.×a
        |¯¯¯¯¯¯¯¯¯|
|¯¯¯¯¯| ||¯¯| |¯¯||
|1 2 3| ||ba| |be||
|_____| ||re| |ar||
        ||__| |__||
        |_________|

|¯¯¯¯¯|
|1 2 3|   |¯¯¯¯¯|
|2 4 6|   |1 2 3|
|3 6 9|   |_____|
|_____|

The last two elements of the system variable ⎕ps determine the row and column spacing between enclosed elements, injecting “box” decorations in one of the spaces if the arguments are negative. The first two elements control the vertical and horizontal positioning of the elements, ¯1 denoting top (or left) justification, 0 centering, and 1 bottom (or right) justification. For example:

   ⎕ps←¯1 1 0 3

   q
1 2 3   ba   be
        re   ar
1 2 3     1 2 3
2 4 6
3 6 9

In later examples it will be convenient to use two further functions. The first is the boolean match (called idem in [3]), denoted by , which compares its left and right arguments and yields a scalar 0 unless they match in every respect. We will also define its monadic case to yield 1 if its argument is simple, that is, contains no enclosed elements.

The second function is a variant of link, defined as follows:

   ;←'(<⍺),∆⍵' ∇ '⍵ ⋄ <⍵ ⋄ →≡⍵'

In words, ;x encloses x if x is simple, and x;y catenates the enclose of x to y , first enclosing y if it is simple. For example:

   ⎕ps←0 0 ¯3 ¯3

   c1;c2
|¯¯| |¯¯|
|ba| |be|
|re| |ar|
|__| |__|

   c1;c2;a
|¯¯| |¯¯| |¯¯¯¯¯|
|ba| |be| |1 2 3|
|re| |ar| |_____|
|__| |__|

   ;⌿c1
|¯¯| |¯¯|
|ba| |re|
|__| |__|

   q≡2 2⍴a;(c1;c2);a∘.×a
1

Theoccurring in the definition of ; is a “self-reference” to the function being defined [3]; since it is used monadically, it refers to the monadic case and therefore encloses its argument if it is simple. It should also be noted that this use of the semicolon as a function need not conflict with its use as a separator in bracket indexing.
 

C. The Disposition of Axes

The effect of an axis operator in an expression such as f⍤1 0 t is simply to apply the function f to the subarrays along the indicated axes of the argument t , and the axes resulting from applying f to each subarray are placed last in the overall result. As simple as these rules are, their effects can be bewildering until the user develops some familiarity with their application in specific instances. Such familiarity can be gained by applying some simple function (such as ravel or scan) in a number of eases:

   ⎕←t←3 2 4⍴⍳124
 0  1  2  3
 4  5  6  7

 8  9 10 11
12 13 14 15

16 17 18 19
20 21 22 23
   ,⍤1 2 t
 0  1  2  3  4  5  6  7
 8  9 10 11 12 13 14 15
16 17 18 19 20 21 22 23

The result of the ravelled 2-by-4 subarrays are placed along the last axis.

   ,⍤0 1 t
0  4  8 12 16 20
1  5  9 13 17 21
2  6 10 14 18 22
3  7 11 15 19 23

The result of the ravelled 3-by-2 subarrays are placed along the last axis.

   ,⍤0 t
0  8 16
1  9 17
2 10 18
3 11 19

4 12 20
5 13 21
6 14 22
7 15 23

Although the ravel of each vector along axis 0 produces no change, the placement of the result along the last axis effects an overall transposition.

   +\⍤0 t
0  8 24
1 10 27
2 12 30
3 14 33

4 16 36
5 18 39
6 20 42
7 22 45

Because the axis resulting from the scan of each vector is placed last, the result differs (by a transposition) from the result of +\[0]t . Compare with the preceding result.

Although the definition of the axis operator used here is adopted from [2], the representation of the right argument i differs slightly; the older definition would be satisfied by replacing f⍤i by f⍤(;i) . In other words, an enclosed right argument is treated as in [2], but a simple argument is treated as a single entity and specifies (in the dyadic case of the resulting function) both the left and right axes of application. For example:

   c1
ba
re
   c2
be
ar
   c1,⍤1 c2
babe
bear
   c1,⍤0 c2
brba
aeer

D. Composition and Related Operators

For a single scalar argument s , the composition of two functions f and g (denoted by f⍤g) is easy to understand, since f⍤g s is equivalent to f g s . For example:

   ⍳⍤⌊ 3.6                ⍳⌊3.6
0 1 2                  0 1 2
   +/⍤⍳⍤⌊ 3.6             +/⍳⌊ 3.6
3                      3

However, much of the importance (and difficulty) of composition stems from its use with non-scalar arguments, in which case the entire composed function f⍤g is applied individually to each of the subarrays to which g (according to its axes of application) applies. For example:

   +/⍤⍳⍤⌊ v← 2.5 3.6 4.9 6.4
1 3 6 15

   ⎕←l← <⍤⍳⍤⌊ v
|¯¯¯| |¯¯¯¯¯| |¯¯¯¯¯¯¯| |¯¯¯¯¯¯¯¯¯¯¯|
|0 1| |0 1 2| |0 1 2 3| |0 1 2 3 4 5|
|___| |_____| |_______| |___________|

   +/⍤> l
1 3 6 15

Note that the expressions +/⍳⌊ and <⍳⌊ and +/> corresponding to the foregoing compositions would not even be valid for the given arguments. In some cases, the corresponding expressions are valid, but yield different results. For example:

   a←3 2 2⍴1 0 1 1 1 0 2 1 1 0 3 1

   a        ⌹a         ⍉⍤⌹a         ⍉⌹a
1 0       1 0       1 ¯1          1  1  1
1 1      ¯1 1       0  1         ¯1 ¯2 ¯3

1 0       1 0       1 ¯2          0  0  0
2 1      ¯2 1       0  1          1  1  1

1 0       1 0       1 ¯3
3 1      ¯3 1       0  1

The operator denoted by ¨ (called with in [2]) applies in two distinct ways. Applied to a function and a variable, it produces the monadic function obtained by supplying the variable as one argument of the (dyadic) function. For example:

   (exp←10¨*) 1 2 3
10 100 1000
   (sq←*¨2) 1 2 3
149

Applied to two functions, as in f¨g , it is equivalent to composition, with a final application of the function gi which is inverse to g . Thus, for a scalar argument s , we have f¨g s ←→ gi f g s . The extension to general arguments is like that of composition. For example:

   +\¨⌽v←1 2 3 4 5
15 14 12 9 5

   ⌈¨(*¨.5) v
1 4 4 4 9

   ⎕←m←3 4⍴⍳12
0  1  2  3
4  5  6  7
8  9 10 11
   +/¨(*¨2⍤0)m Lengths of columns
8.9442719 10.3440804 11.8321569 13.3790882
 
   +/¨(*¨2⍤1)m Lengths of rows
3.74165739 11.22497216 19.13112647

In the foregoing discussion of the operators ¨ and , only the monadic case of the derived function was considered, that is, it was applied to a single argument. The dyadic cases of f⍤g and f¨g are similar, the function g being applied (along appropriate axes) to both the left and right arguments. For example:

   a +⍤÷ b←1+a←1 2 3
1.5 0.83333333 0.58333333
   a+¨÷b
0.66666667 1.2 1.71428571
   c ×⍤(+/⍤0) c←3 3⍴⍳9
81 144 225

The composition in the expression a f⍤g b (referred to in [2] as f on g) applies the dyadic (case of the) function f to the results of the monadic function g ; the composition in the expression a f⍥g b (to be referred to as f upon g) applies the monadic function f to the result of dyadic g , as in f a g b . The difference may be illustrated as follows:

   c1             c2
ba             be
re             ar

   c1 ,⍤, c2
barebear
   c1 ,⍥, c2
baberear
   a <⍤÷ b←⌽a←1 2 3 4
0 0 1 1
   a <⍥÷ b
|¯¯¯¯| |¯¯¯¯¯¯¯¯¯¯| |¯¯¯| |¯|
|0.25| |0.66666667| |1.5| |4|
|____| |__________| |___| |_|

We will conclude this section with a rather complex expression involving operators, the purpose being to illustrate how to “read” such expressions. If:

   a←2 3 4 5⍴⍳120
   v←(i←1);(j←2 0);(k←3);(l←4 2 0)

then it is possible to write a function of v such that the ravel of a indexed by its result is equivalent to a[i;j;k;l] . Thus:

   a[i;j;k;l] ≡ (,a)[>∘.+¨>/vר>r⊥⍳⍴r←⍴a]

An understanding of the expression in the brackets can be gained by executing it piece-by-piece:

   ⎕←z←r⊥⍳⍴r←⍴a
60 20 5 1
   v
|¯| |¯¯¯| |¯| |¯¯¯¯¯|
|1| |2 0| |3| |4 2 0|
|_| |___| |_| |_____|
   ⎕←y←v ר> z
|¯¯| |¯¯¯¯| |¯¯| |¯¯¯¯¯|
|60| |40 0| |15| |4 2 0|
|__| |____| |__| |_____|
   ∘.+¨>/y
|¯¯¯¯¯¯¯¯¯¯¯|
|119 117 115|
| 79  77  75|
|___________|

The expression for z (whose details were shown in Section A) yields the weights appropriate to the successive axes in indexing the ravel of the argument a . The vector y is obtained by multiplying each element of the list of indices (v) by the appropriate weight, and the final result shown is the application of the plus-outer-product (∘.+) between each of the disclosed elements of y .
 

E. The Definition of Operators

A dyadic operator can be defined in terms of expressions involving its two arguments (to be denoted by and and the two arguments of the derived function produced (to be denoted byand). For example, if the dyadic operator were defined by the expression '(⍺)×⍵' ∇ '⍵∆⍵' , then 3.5 ⌊⌈ 6.5 would yield 21 , and 3.5 ⌈⌊ 6.5 would yield 24 .

Since either or both of the arguments or may be either a variable or a function, and since definitions must sometimes be provided for two or more of the four possible cases, each definition will be associated with an indication of the case it defines. For example, if

←(1 1;0 1) ∇ ('''(⍺)×⍵''∇''⍵∆⍵'''; '''''∇''¨×⍤⍵''')

then behaves as described above, and 3⌈ 6.5 yields 21 .

In general, the definition of a dyadic operator requires as the left argument of a vector whose kth element is the enclosed representation (using 0 to denote a variable and 1 to denote a function) of the case represented by the kth element of the right argument. In the definition of a monadic operator, each case is indicated by a single quantity, and the left argument of is therefore one of 0 , or 1 , or 0;1 , or 1;0 .

We will conclude this section with the definition of a new dyadic operator denoted by (and called til as an abbreviation of tilde):

   ⍨←1 1 ∇ '''(⍵)⍺''∇''⍵∆⍵'''

This operator is of great practical interest because it subsumes a number of important special cases arising from its use with the identity function (defined as ⊢←'⍵'∇'⍵'), and with a sequence of functions, as in f⍨g⍨h :

a) 

Since

   ⍺ f⍨⊢⍵ ←→ (⊢⍵) f ⍺ ←→ ⍵ f ⍺

the function f⍨⊢ is the commutation of f .
 .

b) 

Since

   ⍺ f⍨g⍨h ⍵ ←→ (g⍺) f (h⍵)
     f⍨g⍨h ⍵ ←→ (g⍵) f (h⍵)

the operator til provides a generalization of the operators illustrated above, for instance by the operator , applying an arbitrary dyadic function f to the results of two monadic functions g and h . Moreover, the use of the identity function for either g or h provides cases which might be called “left composition” and “right composition”:

   f⍨g⍨⊢⍵ ←→ (g⍵) f ⍵
   f⍨⊢⍨h⍵ ←→ ⍵ f (h⍵)

For example, if the propositions p and q are defined by p←2¨| and q←3¨< , then:

   ^⍨p⍨q v←1 2 3 4 5 6 7
0 0 0 0 1 0 1

   ∨⍨p⍨q v
1 0 1 1 1 1 1

   +⍨p⍨q v
1 0 1 1 2 1 2

Finally, the function cf (defined in the introduction by '⍺+÷⍵'∇'⍵∆⍵') may now be defined by cf←+⍨⊢⍨÷ or, since + is commutative, by cf←+⍨÷ , and the expression for indexing the ravel of an array a (given at the end of Section D) can now be defined by:

   q←>⍥(∘.+¨>/)⍥(ר>⍤¯1⍨(⊥⍨⍴⍨(⍤⍳⍤⍴⍤⍴)))

F. Merge as a Dyadic Case of Selection

If s is a dyadic selection function such that i s a selects from a an array determined by the “indices” (or other parameters) provided by the variable i , then the derived function i¨s is a derived selection function which is monadic, and selection from a is obtained by the expression i¨s a . For example, if m←3 3⍴⍳9 , then 0 0¨⍉ is a monadic selection function such that 0 0¨⍉ selects the diagonal vector 0 4 8 when applied to m .

Consider a definition of the dyadic case of such a derived function which returns the entire right argument, but with the elements of the left argument substituted for the selected elements of the right argument. The dyadic function therefore provides a merge of its arguments. For example:

   m←3 3⍴⍳9
   m                       (10+⍳3) 0 0 ¨⍉ m
0 1 2                   10  1  2
3 4 5                    3 11  5
6 7 8                    6  7 12

This definition of a dyadic case will be extended to other selection functions in the same manner. Consider, for example, the following indexing function, defined in terms of the function q defined at the end of the preceding section:

   s←'(,⍵)[⍵q⍺]'∇''
   ⎕←i←?4 2⍴3              i s m
1 2                     5 6 0 3
2 0
0 0
1 0

The function(called from) is incorporated in the model using the definition of s above, but adopting the merge definition for the dyadic case of the derived function i¨⌷ . Thus:

   (10+⍳4) i¨⌷ m
12 1  2
13 4 10
11 7  8

A different approach to the treatment of merge functions may be found in [4].
 

G. Function Attributes

An APL function is defined not only by the result it produces for each argument in its domain, but by certain attributes, some of which (like the axes of application) are manifest in every use of the function, and some of which (like the identity element and the inverse) become manifest only upon the application of some operator. For example, the results of the functions ^ andare identical for boolean arguments, but differ in their identity elements, ^/⍳0 yielding 1 , and ⌊/⍳0 yielding infinity; the inverse of a function is manifested in the application of the dual operator.

The representation of attributes will be introduced into the representation of functions as follows: any segment (as delimited by diamonds) which begins with a right parenthesis represents an attribute; the first token following the parenthesis denotes the name of the attribute specified, and what follows (after the delimiting space) specifies the attribute.

For example, the name ∆⌿ denotes the identity element attribute, and the expression mp←'⍺+.×⍵ ⋄)∆⌿ ⍳1↑⍴⍵'∇'' defines mp as a matrix product function whose identity function produces an identity matrix of appropriate shape. Thus, if ⍴a ←→ 5 4 4 , then mp ⌿ 5 0 0↓a is a 4-by-4 identity matrix.

The following is a list of attributes (together with suggested names) which we have found useful and have incorporated into the APL model:

1. 

Axes (∆⍤)

The axes of application, which may be specified independently for the monadic and dyadic cases.
 

2. 

Scope (~;)

The names to be exempted from the localization otherwise applied to names which are assigned values within a function. Except for the inclusion of the name (~;) for identifying the attribute, the scheme agrees with that proposed in [3].
 

3. 

Identity Element (∆⌿)

The identity elements associated with the primitive functions are (because limited to scalar functions) all constants; in the more general case they may, like the example of matrix product given above, be functions of the shapes of the arguments.
 

4. 

Merge (¨∆⍵)

This attribute will indicate that the derived function ¨∆ (for a variable ) is a selection function which extends to a merge in the dyadic case in the manner discussed in Section F.
 

5. 

Inverse (∆⍣¯1)

This attribute gives the inverse function to be used when the dual operator is applied to the function. The name ∆⍣¯1 used above arises from the power operator incorporated in the model (which applies its monadic left argument the number of times specified by the variable right argument). The result of f⍣¯1 is the inverse of f . For example, *⍣¯1 is equivalent to .
 

6. 

Inverses: left and right cases (⍺¨∆⍣¯1) (∆¨⍵⍣¯1)

If v is a variable and f is a function, then v¨f produces a monadic function (the left case of f), and f¨v produces a function, either or both of which may possess inverses. These attributes provide the appropriate inverses.

For example, the inverses of +¨v and v¨+ are both (-v)¨+ , the inverse of -¨v is +¨v , and v¨- is self-inverse.
 

7. 

Derivative ()

The model incorporates the specification of derivatives for a few cases. For example, 1¨○ is equivalent to 2¨○ .
 

8. 

Variant (∆:)

The model provides a few cases of the variant operator discussed in [1]. For example, (⍳:1) 3 is 1 2 3 , and (⍳:0) 3 is 0 1 2 . This use of the colon need not conflict with the present use provided that (as proposed for the double use of the semicolon) the older usage is given priority. Thus the colon in l:a b c at the beginning of an expression will indicate that l is a label, and the use of the variant l:a would (at the beginning of an expression) have to be indicated by parentheses, as in (l:a) b c .
 

References

1.  Iverson, K.E., Operators and Functions, Research Report #RC7091, IBM Corp., 1978.
2.  Bernecky, R., and Iverson, K.E., Operators and Enclosed Arrays, APL Users Meeting, I.P. Sharp Associates, 1980.
3.  Iverson, K.E., and Wooster, P.K., A Function Definition Operator, APL Quote Quad, Vol.12, No.1, Sept. 1981 (Proceedings of APL81).
4.  Pesch, R.H., Indexing and Indexed Replacement in APL, APL Quote Quad, Vol.12, No.1, Sept. 1981.


First appeared in APL82, APL Quote-Quad, Volume 13, Number 1, 1982-09.

created:  2009-10-10 21:30
updated:2012-08-29 21:25