💾 Archived View for blitter.com › apl-books › RationalizedAPL › www.jsoftware.com › papers › Rationa… captured on 2024-08-25 at 04:12:33.
⬅️ Previous capture (2022-07-17)
-=-=-=-=-=-=-
<html> <head><meta http-equiv="content-type" content="text/html;charset=utf-8"> <title>Rationalized APL</title> <link href="adoc.css" rel=stylesheet> </head> <body> <br> <table width=520 align=center><tr><td> <p align=center><font size=+2>Rationalized APL</font><br><br> <b>Kenneth E. Iverson<br> I.P. Sharp Associates<br>Toronto</b></p> <p align=center>I.P. Sharp Research Report #1<br> Rev. 1 - 4 April 1983</p> <br><hr> <a name="intro"></a> <p>Certain aspects of <b>conventional</b> APL (as defined in the IBM publication <b>APL Language</b> <acronym title="APL Language (IBM Corporation, GC26-3847)">[1]</acronym>) violate some of the fundamental characteristics of the language, and the definitions of some other aspects are too limited to provide clear guidance for systematic extensions. The present paper proposes convenient replacements for the anomalous facilities, and a systematic scheme for extensions, a scheme that does not invalidate the facilities defined in <acronym title="APL Language (IBM Corporation, GC26-3847)">Reference 1</acronym>, nor, indeed, those incorporated in many other systems, specifically SHARP APL.</p> <p>The main aspects to be treated are:</p> <table> <tr><td>A)</td><td> </td><td>Bracket and semicolon indexing, and indexed assignment.</td></tr> <tr><td>B)</td><td> </td><td>Name assignment.</td></tr> <tr><td>C)</td><td> </td><td>Function valence.</td></tr> <tr><td>D)</td><td> </td><td>Function definition.</td></tr> <tr><td>E)</td><td> </td><td>Syntax and order of execution.</td></tr> <tr><td>F)</td><td> </td><td>Extensions to higher rank arrays.</td></tr> <tr><td>G)</td><td> </td><td>Operators on non-scalar functions.</td></tr> <tr><td>H)</td><td> </td><td>Miscellaneous.</td></tr> </table> <p>Items in the foregoing list can be used to illustrate the main point. For example, the indexing<tt> a[i;j] </tt>cannot (without the use of<tt> ⍎</tt> )<tt> </tt>be applied to an array<tt> a </tt>of arbitrary rank, the list expression<tt> (i;j) </tt> must be treated as a monolithic whole (i.e., not as a sequence of normal APL functions), and a name cannot be assigned to the resulting list. The reduction and inner and outer product operators are limited to scalar functions and could be extended in a variety of ways. For example, the reduction<tt> f⌿a </tt>could (as it is in <acronym title="APL*PLUS Nested Array System (STSC, Inc., 1981)">[2]</acronym>) be assumed to apply<tt> f </tt>over each vector along the leading axis of<tt> a</tt> ,<tt> </tt> or it could (as defined in <acronym title="APL2 Language Manual (IBM Corporation, SB21 3015, June 1982)">[3]</acronym>), apply<tt> f </tt>over the set of subarrays obtained by splitting<tt> a </tt>along the first axis. Both are consistent with the conventional definition, but only the latter allows the matrix product over a rank three array to be expressed as<tt> +.×⌿a</tt> .</p> <p>A section will be devoted to each of the eight items listed above, and additional sections will treat a number of new functions and operators defined according to the schemes developed in the earlier sections. Two appendices summarize the ranks assigned to existing primitive functions (to systematize all extensions to higher-rank arrays), and the definitions of dyadic operators.</p> <p>Any problems attendant upon the use of implicit arguments such as<tt> ⎕io </tt>are exacerbated by the more general uses of operators. Consequently, all new functions and operators to be defined will be <b>independent of</b><tt> ⎕io</tt> ,<tt> </tt> <b>and will be defined in origin</b><tt> 0</tt> . Moreover,<tt> 0</tt>-origin will be used throughout this paper.</p> <p>Consider, for example, the operator<tt> ⍥ </tt>which we will define so that the function<tt> g←f⍥i </tt>applies<tt> f </tt> to its argument after transposing to the rear end those axes specified by<tt> i</tt> .<tt> </tt> If the operator is independent of<tt> ⎕io </tt>(and uses fixed origin 0), then a function<tt> g </tt>that moves the leading axis to the rear is obtained from the expression<tt> g←f⍥0</tt> .<tt> </tt> However, if dependence on<tt> ⎕io </tt>were to be adopted, which value of<tt> ⎕io </tt>should apply, that in effect when<tt> g </tt>is specified, or when it is used? If the former, what advantage does the dependence offer, and if the latter, how could one specify the desired behaviour in the unknown environment?</p> <p>The reader is assumed to be familiar with the functions <b>enclose</b>, <b>disclose</b>, and <b>match</b> (<tt>< > ≡</tt>)<tt> </tt>as defined in <acronym title="Robert Bernecky and Kenneth E. Iverson, Operators and Enclosed Arrays (I.P. Sharp, Proceedings of the User Meeting, 1980)">[4]</acronym>, Moreover, we will assume that the symbol<tt> ∘ </tt>denotes the constant<tt> <''</tt> ;<tt> </tt>that is<tt> ∘≡<''</tt> .<tt> </tt> This provides a convenient notation for a “fill” element appropriate to a non-simple array, just as<tt> 0 </tt>and<tt> ' ' </tt> provide fill elements for simple arrays. Moreover, it rationalizes the use of the symbol<tt> ∘ </tt> in the outer product, so that the expression<tt> a.b </tt> may be used with<tt> a←∘ </tt>(or<tt> a←<''</tt> )<tt> </tt> and<tt> b←×</tt> ,<tt> </tt> just as it may be used with<tt> a←+ </tt>and<tt> b←×</tt> .</p> <p>An interpreter for the language as extended here (written in APL) has proved invaluable in developing the design, and it has been used to produce the examples used herein. Any reader having access to this interpreter (in workspace<tt> 705 model </tt>on the I.P. Sharp system) will find it helpful in studying the present paper. An early version of the interpreter has been presented in <acronym title="K.E. Iverson, APL Syntax and Semantics (ACM, APL83)">[5]</acronym>; except as it may prove useful in the treatment of language questions, the interpreter itself will not be discussed here.</p> <p>To obviate repetitions of phrases such as “if<tt> a </tt>is an array of rank<tt> 3</tt> ”,<tt> </tt> we will adopt the following convention:<tt> a0</tt> ,<tt> b0</tt> ,<tt> </tt>etc., denote scalars,<tt> a1</tt> ,<tt> b1</tt> ,<tt> </tt> etc., denote vectors, and so forth.</p> <p><b>Appendices.</b> The body of the paper is devoted to definitions of the proposed extensions, and does not include examples of their use. Such examples are provided in <a href="RationalizedAPL1.htm#xc">Appendix C</a>, and many readers will find it more fruitful to go directly to this appendix before studying the complete definitions. In order to make such a course feasible, simplified definitions are included in the appendix.</p> <p><a href="RationalizedAPL1.htm#xa">Appendices A</a> and <a href="RationalizedAPL1.htm#xb">B</a> show a table of ranks assigned to existing primitive functions, and a table of the new dyadic operators proposed. A final appendix (<a href="RationalizedAPL1.htm#xd">D</a>) provides a general comparison of APL2 <acronym title="APL2 Language Manual (IBM Corporation, SB21 3015, June 1982)">[3]</acronym> with a restricted subset of the proposals in this paper.</p> <br><a name="a"></a> <p><b>A. Indexing and Indexed Assignment</b></p> <p>The enclose function as defined in <acronym title="Robert Bernecky and Kenneth E. Iverson, Operators and Enclosed Arrays (I.P. Sharp, Proceedings of the User Meeting, 1980)">[4]</acronym> has made it possible to produce by straightforward APL functions the “index lists” required in indexing expressions of the form<tt> a[i;j]</tt> ,<tt> </tt> and therefore makes it possible to define a corresponding indexing function, which will be denoted by<tt> { </tt> and called <b>from</b>:</p> <pre> i{a ←→ a[>i[0];>i[1]; ...] </pre> <p>Since the disclose function<tt> > </tt>is permissive, the selection of any single element of<tt> a </tt> can be written without enclosures as, for example,<tt> 1 2 3{a3</tt> .<tt> </tt> Moreover, the left rank of<tt> { </tt>is<tt> 1 </tt> and its right rank is infinite, so that (as discussed in <a href="RationalizedAPL1.htm#f">Section F</a>) a simple left argument<tt> i </tt>of rank greater than<tt> 1 </tt>produces an array of shape<tt> ¯1↓⍴i </tt>of elements chosen by the index vectors along its last axis, yielding what is sometimes called “scattered” indexing. For examp1e:</pre> <pre> (3 2⍴⍳6){a2 ←→ a2[0;1],a2[2;3],a2[4;5] </pre> <p>Each index<tt> >i[k] </tt>must be of the form<tt> s </tt>or<tt> <s</tt> ,<tt> </tt> where<tt> s </tt>is a simple array. If<tt> >i[k] </tt>is of the form<tt> <s</tt> ,<tt> </tt> then the indexing along axis<tt> k </tt>is complementary, selecting all elements except those whose indices occur in<tt> >>i[k]</tt> .<tt> </tt> In particular, if<tt> i[k]≡<<⍳0</tt> ,<tt> </tt> the entire axis is selected.</p> <p>In forming the left arguments of the indexing function, it will often be convenient to use the link function<tt> ⊃ </tt>defined as follows:</p> <table> <tr><td><tt> ⊃b ←→ <b </tt>if<tt> b </tt>is simple</td></tr> <tr><td><tt> b </tt>if<tt> b </tt>is non-simple</td></tr> <tr><td> </td></tr> <tr><td><tt> a⊃b ←→ (<a),⊃b</tt></td></tr> </table> <p>For example,<tt> (2 3⊃4⊃∘⊃5 6){a4 ←→ a[2 3;4;;5 6]</tt> .</p> <p>The indexing function<tt> { </tt>as defined thus far provides all of the facilities provided by conventional indexing, and “scattered” and “complementary” indexing as well. Its power is further enhanced by allowing <b>negative</b> indexing (with the completely disclosed element<tt> e </tt> in position<tt> k</tt> ,<tt> </tt> either<tt> >k{i </tt>or<tt> >>k{i</tt> ,<tt> </tt> replaced by<tt> (k{⍴a)|e</tt> )<tt> </tt> and <b>abbreviated</b> indexing (with<tt> i{a </tt>equivalent to<tt> (i,((⍴⍴a)-⍴i)⍴<∘){a</tt> ).<tt> </tt> For example,<tt> 2 3{a3 ←→ (2⊃3⊃<∘){a3 </tt> and, if<tt> ⍴a </tt>is<tt> 2 3 4</tt> ,<tt> </tt> then<tt> 1 ¯1 1 {a ←→ a[1;2;1]</tt> .<tt> </tt> Each index<tt> j </tt>along an axis of length<tt> n </tt> is limited by<tt> (j<n)∧(n≥-j)</tt> .</p> <p>Indexed assignment of the form<tt> a[j;k]←b </tt>is anomalous, or at least awkward; the result of the expression (as received by<tt> c </tt>in<tt> c←a[j;k]←b</tt> )<tt> </tt> is merely<tt> b</tt> ,<tt> </tt> and the merged result normally wanted must be obtained by a separate reference to<tt> a</tt> .</p> <p>What is desired is a merge of<tt> a </tt>and<tt> b </tt> controlled by an index<tt> i </tt>and by the particular selection function employed. A simple solution is provided by the <b>with</b> operator<tt> ¨ </tt> (described in <acronym title="K.E. Iverson, Operators and Functions (IBM Corporation, RC7091, 1978)">[6]</acronym> as<tt> a¨f x ←→ a f x</tt> )<tt> </tt> combined with the observation (made by Arthur Whitney) that a dyadic case of the derived function<tt> i¨{ </tt> could be defined to produce the desired merge. Thus if:</p> <pre> r←b i¨{ a </pre> <p>then<tt> (⍴r)≡⍴a</tt> ,<tt> </tt>and<tt> b≡i{r</tt> ,<tt> </tt> and “the rest” of<tt> r </tt> agrees with the rest of<tt> a</tt> ,<tt> </tt>Thus:</p> <pre> a2[j;k]←b ⋄ a2←⍉a2 ←→ a2←⍉b (j⊃k)¨{a2 </pre> <p>In order to avoid the questions raised by expressions such as<tt> x[1 1]←2 3</tt> ,<tt> </tt> it might be desirable to restrict the domain of the expression<tt> b i¨{a </tt> to a “proper” index<tt> i </tt> containing no repeated elements. On the other hand, a permissive definition may be harmless, and could probably be implemented more easily.</p> <br><a name="b"></a> <p><b>B. Name Assignment</b></p> <p>In conventional APL, the arrow used for assigning a name to a variable is not permitted for naming functions. Instead, a function name is assigned indirectly by characters embedded in its representation, and there is no direct way for assigning a name to a derived function such as<tt> +.×</tt> .</p> <p>The solution is to allow the arrow to assign a name to any entity — variable, function, or operator (as in<tt> x←⍳5 </tt> and<tt> ip←+.× </tt>and<tt> red←/</tt> ) — and to provide means for function definition that do not embed the function name in its representation. This is discussed in <a href="RationalizedAPL1.htm#d">Section D</a>.</p> <br><a name="c"></a> <p><b>C. Function Valence</b></p> <p>In conventional APL, functions are generally considered to be ambivalent, with the actual valence of application being determined by context. Many, however, are assigned a fixed valence — some primitives (e.g., monadic<tt> ~ </tt>and dyadic<tt> ∊</tt> ),<tt> </tt> most derived functions (with one exception,<tt> ⌽[i]</tt> ),<tt> </tt> and all defined functions.</p> <p>The introduction of ambivalent defined functions in many APL systems has proved very convenient to the user, and the admission of ambivalent derived functions opens up many new possibilities, one of which has been exploited in the use of<tt> -.×m </tt> for the determinant <acronym title="K.E. Iverson, Determinant-Like Functions Produced by the Dot Operator (I.P. Sharp Technical Notes - SATN-42, April 1982)">[7]</acronym>.</p> <p>It is now proposed that (except for niladic functions, which must be treated separately), all functions be assumed to be ambivalent, and that any undefined case (such as<tt> ∊x</tt>) be treated as a proper function which has an empty domain. An unfortunate consequence of this is that <b>some change will occur</b> in the behaviour of existing programs, but only in replacing a syntax error message by a domain error message, or (as in the case of<tt> ~/3</tt> )<tt> </tt>by a result. However, this is a single, general change that would prevent further changes occasioned by each function extension introduced. Niladic functions must, of course, retain their fixed valence.</p> <p>A further consequence of the ambivalence of all functions is that no operator can have its behaviour defined in terms of the valence of the function to which it is applied, since all have the same valence. This matter was anticipated in <acronym title="Robert Bernecky and Kenneth E. Iverson, Operators and Enclosed Arrays (I.P. Sharp, Proceedings of the User Meeting, 1980)">[4]</acronym> in the definition of two distinct composition operators, one to apply a function<tt> f </tt> dyadically to the results of monadic applications of<tt> g </tt> (as in<tt> ⍺ f⍤g ⍵ ←→ (g⍺) f (g⍵)</tt> ),<tt> </tt> and one to apply<tt> f </tt>monadically to the result of a dyadic application of<tt> g </tt>(as in<tt> ⍺ f⍥g ⍵ ←→ f ⍺g⍵</tt> ).</p> <br><a name="d"></a> <p><b>D. Function Definition</b></p> <p>Although the operators are the entities generally used to produce functions in APL, the only language facility (as opposed to the<tt> ∇</tt>-editing facility based upon it but not usable in programs) provided for producing defined functions (i.e.,<tt> ⎕fx</tt> ),<tt> </tt>is itself a <b>function</b>, and one which produces as an explicit result only the <b>name</b> of the function, producing the function itself as a side-effect. Moreover, although many APL systems allow<tt> ⎕fx </tt> to produce ambivalent functions, none provide true ambivalence, with, for example, independent localization of variables for the two cases.</p> <p>The proposed replacement for<tt> ⎕fx </tt>is a modification of the direct definition operator<tt> ∇ </tt>defined in <acronym title="Kenneth E. Iverson and Peter K. Wooster, A Function Definition Operator (APL Quote Quad, Volume 12, Number 1, Proceedings of APL81, ACM September 1981)">[8]</acronym>, and is defined as follows:</p> <table> <tr><td valign=top>1.</td><td> </td><td> <tt>m∇d </tt>produces a function, with<tt> m </tt>and<tt> d </tt> being the representations of the monadic and dyadic cases. <br> </td></tr> <tr><td valign=top>2.</td><td> </td><td> The general form of each representation is a vector<tt> r </tt> of enclosed <b>segments</b>, the segments being executed in an order determined by a <b>sequence control</b> vector. It is initially set to<tt> 1+⍳⍴r </tt> (the segment indices beginning at<tt> 1 </tt>as do the indices in conventional definition), and is reset by any branch statement having a non-empty argument. Termination occurs upon exhaustion of the sequence control vector, or upon an index out of range. <br> </td></tr> <tr><td valign=top>3.</td><td> </td><td> A label in the first element of<tt> r </tt>is assigned the value<tt> 1+⍳⍴r</tt> ,<tt> </tt> one in the second is assigned<tt> 1↓1+⍳⍴r</tt> ,<tt> </tt>etc. A label is indicated by a right parenthesis rather than a colon, freeing the colon for use as a variant operator as suggested in <acronym title="K.E. Iverson, Operators and Functions (IBM Corporation, RC7091, 1978)">[6]</acronym>. <br> </td></tr> <tr><td valign=top>4.</td><td> </td><td> The symbols<tt> ⍺ </tt>and<tt> ⍵ </tt>denote the left and right arguments, and<tt> ∆ </tt>is used for <b>self-reference</b> to the function itself, being used in recursive definitions as well as for defining one of the two cases in terms of the other. <br> </td></tr> <tr><td valign=top>5.</td><td> </td><td> A name is localized if it occurs <b>immediately</b> to the left of an assignment arrow in any segment; for example,<tt> 3×a←4+b ←⍵ </tt> localizes<tt> a </tt>but not<tt> b</tt> .<tt> </tt> Name localizations for the monadic and dyadic cases are independent. <br> </td></tr> <tr><td valign=top>6.</td><td> </td><td> The explicit result of a function is the result of the last statement executed which produced an explicit result, where expressions such as<tt> x←3+4 </tt>or<tt> 3+4 </tt>are assumed to produce explicit results, but<tt> →a </tt> and<tt> ⍎'' </tt>and<tt> ⊣a </tt> (as defined in <a href="RationalizedAPL1.htm#j">Section J</a>) are not. Automatic output is not produced by an expression such as<tt> 3+4</tt> ;<tt> </tt> such output is produced only by expressions using<tt> ⎕←</tt> . <br> </td></tr> <tr><td valign=top>7.</td><td> </td><td> Every vector<tt> v </tt>is treated as<tt> ,⊃v</tt> ,<tt> </tt>that is, a simple vector is treated as a single segment. Single segments may therefore be written in the form<tt> '0⌈⍵' ∇ '⍺||⍵' </tt>. </td></tr> </table> <p>A function produced by the operator<tt> ∇ </tt> may be assigned a name (as in<tt> f←m∇d </tt> or in<tt> a(f←m∇d)b</tt> ),<tt> </tt> but it may also be used without assigning a name, as in <tt> y←''∇'⍺+÷⍵'/x</tt> .</p> <br><a name="e"></a> <p><b>E. Syntax and Order of Evaluation</b></p> <p>Although the order of execution of functions and operators in conventional APL is well-defined, the order of <b>evaluation of names</b> is not, and ambiguity therefore occurs not only in an expression such as<tt> (a←2)÷a←3</tt> ,<tt> </tt>but also (if<tt> a </tt>is a shared variable) in the simpler expression<tt> a÷a</tt> .<tt> </tt> The matter is further complicated by allowing the direct assignment of names, as in<tt> (f←3×⍳4)(f←×.-)f←⍳4</tt> .</p> <p>Although the precedence of operators over functions is established in conventional APL, the fact that operators are not applied to derived functions implies that the syntax and order of execution of a sequence of operators is not established. The syntax and order of evaluation and execution that is now widely accepted (and is proposed here) may be summarized as follows:</p> <table> <tr><td valign=top>a)</td><td> </td><td> Parentheses are obeyed as usual, and are permitted around function names, as in<tt> a(+)b <tt>and<tt> a(+.×)b</tt> . <br> </td></tr> <tr><td valign=top>b)</td><td> </td><td> Names are evaluated in order from right to left, and the values produced are detached from the original names. <br> </td></tr> <tr><td valign=top>c)</td><td> </td><td> An operator may be either monadic or dyadic, but is not ambivalent. <br> </td></tr> <tr><td valign=top>d)</td><td> </td><td> An operator applies to the result of the entire operator sequence to its left, much as a function applies to the result of the entire expression to its right. Thus<br><br> <tt>* +.×/t ←→ *(+.×)/t</tt> . </td></tr> </table> <p>More precisely:</p> <p>1. The tokens (i.e., the indivisible names such as<tt> abc </tt>or<tt> ¯2.4e5 </tt>or<tt> + </tt> or<tt> ¯2.4e5 3 2</tt> )<tt> </tt> are examined in order from right to left; each is evaluated immediately and the representation of the result (whether variable, function, or operator) is appended at the beginning of a (<b>right</b>) <b>stack</b> vector and is immediately dissociated from the name whose evaluation yielded it.</p> <p>2. The evaluation of tokens may be interrupted by the execution of a function or operator in the stack applied to one or two adjacent arguments in the stack.</p> <p>3. The syntax and order of execution are further specified by a set of rules that determine what segment of the stack is to be executed, or whether evaluation of tokens is to proceed. The rules are based upon the class (variable, operator, function, assignment arrow) of each of the first four elements of the stack.</p> <p>4. A right parenthesis invokes the execution of the entire expression up to the matching left parenthesis, the result being then transferred to the right stack.</p> <p>5. Because conventional APL uses name assignment in the form<tt> ab←x </tt>rather than in the possible, but more awkward, form<tt> 'ab'←x</tt> ,<tt> </tt> rule 1 above must be modified as follows: if the leading element in the right stack is an assigment arrow, the next token is transferred directly without evaluation.</p> <p>6. Items 4 and 5 conflict in the case<tt> (n)←3</tt> ,<tt> </tt> a conflict resolved by giving precedence to item 4. The consequence (as elaborated in <acronym title="K.E. Iverson, APL Syntax and Semantics (ACM, APL83)">[5]</acronym>) is to provide “indirect” assignment. For example, if<tt> n←'asd' </tt>and<tt> (n)←3 </tt> ,<tt> </tt> then<tt> n </tt>retains the value<tt> 'asd'</tt> ,<tt> </tt> and<tt> asd </tt>becomes<tt> 3</tt> .</p> <p>7. The rules referred to in item 3 are summarized in the following table taken directly from the interpreter:</p> <pre> vmf←l vf d vf L S(1↑R),(R[2]RE R[1 3]),4↓R vmf←l v f v L S(1↑R),(R[2]RE R[1 3]),4↓R vmf←l vf m L S(1↑R),(R[2]RE R[1]),3↓R mf←l f v L S(1↑R),(R[1]RE R[2]),3↓R d v f v L S(2↑R),(R[2]RE R[3]),4↓R v ← vmdf r L S,R[0] IS R[2] l vmdf r R[1] vmdfr (>''⍴Z)S(1↓Z←L LE 0),R ← (>''⍴Z)S(1↓Z←L LE 1),R R not single∊ </pre> <p>Each of the first four columns above specifies the classes to which the corresponding element of<tt> R </tt> may belong to invoke the corresponding action specified by the final column. The symbols<tt> v</tt> ,<tt> m</tt> ,<tt> d</tt> ,<tt> f</tt> ,<tt> ←</tt> ,<tt> l</tt> ,<tt> </tt> and<tt> r </tt>denote the classes <b>variable</b>, <b>monadic operator</b>, <b>dyadic operator</b>, <b>function</b>, <b>assignment</b>, <b>left</b> (a filler introduced when the left stack is exhausted), and a <b>right filler</b> implicitly introduced to extend a short right stack to four elements.</p> <p>Thus the first line specifies the action to be taken (replacing elements<tt> 1</tt> ,<tt> 2</tt> ,<tt> 3 </tt>of the stack by the result of applying element<tt> 2 </tt>[a dyadic operator] to elements<tt> 1 </tt>and<tt> 3</tt> )<tt> </tt> in the case that<tt> R[0] </tt> belongs to any one of the classes<tt> vmf←l</tt> ,<tt> </tt> and<tt> R[1] </tt>belongs to<tt> vf </tt>and<tt> R[2] </tt>belongs to<tt> d</tt> ,<tt> </tt> and<tt> R[3] </tt>belongs to<tt> vf</tt> .</p> <p>No special treatment is required for a niladic function (represented in the usual way) since it is executed (exactly as a variable is) before being transferred to the right stack. Further entries could be added at the head of the syntax table to catch invalid sequences in the right stack as soon as they occur, rather than allowing them all to appear as a single error due to the fact that the stack has the wrong form upon termination.</p> <br><a name="f"></a> <p><b>F. Extensions to Higher Rank Arrays</b></p> <p>In conventional APL, the scalar functions (which apply to scalar elements and produce scalar results) extend to higher rank arrays according to simple general rules; no corresponding general rules exist for the remaining so-called mixed functions. We will now define a systematic scheme of extensions based on two attributes of a function: <b>rank</b>, and <b>conformance</b>.</p> <a name="f1"></a> <p><b>Rank.</b> For a general function<tt> f</tt> ,<tt> </tt> the axes of an argument<tt> ⍵ </tt>will be split at some point<tt> k </tt> such that<tt> f </tt>is applied to each subarray of shape<tt> k↓⍴⍵</tt> ,<tt> </tt>producing a result of shape<tt> (k↑⍴⍵),sir</tt> ,<tt> </tt> where<tt> sir </tt>is the (necessarily common) shape of the individual results produced by applying<tt> f </tt>to each subarray.</p> <p>Each function<tt> f </tt>is assigned a monadic rank<tt> mf </tt> which determines the value of<tt> k </tt>as follows:</p> <table> <tr><td><tt> k←0⌈(⍴⍴⍵)-mf</tt></td><td> </td><td>if<tt> mf≥0</tt></td></tr> <tr><td><tt> k←(⍴⍴⍵)⌊|mf</tt></td><td> </td><td>if<tt> mf<0</tt></td></tr> </table> <p>Consequently, a positive or zero value of<tt> mf </tt> determines the rank of the subarrays to which<tt> f </tt>applies, and a negative value determines the <b>complementary</b> rank, the number of <b>leading</b> axes excluded in each application of<tt> f</tt> .</p> <p>Because of the definition of<tt> k</tt> ,<tt> </tt> the rank of a function imposes only an upper limit on the rank of the subarrays to which<tt> f </tt>applies, and does not prohibit the application of<tt> f </tt>to <b>degenerate</b> cases of lower rank. For example, the function<tt> ⌹ </tt>has rank<tt> 2</tt> ,<tt> </tt> but if its argument is a vector it is applied to the vector. Because the function<tt> ⌹ </tt>is defined on vectors, it yields a result, although another rank<tt> 2 </tt>function, such as the determinant, might be defined to yield a domain error in such a degenerate case.</p> <p>Similar remarks apply to the dyadic case, with each function being assigned independent left and right ranks, and yielding outer shapes<tt> ol←kl↑⍴⍺ </tt>and<tt> or←kr↑⍴⍵</tt> .<tt> </tt> The agreement required between these outer shapes will be discussed under the heading “conformance”.</p> <p>Certain functions, such as ravel, are of <b>infinite</b>, or <b>unbounded</b> rank; consistently with the foregoing definition, such a rank will be assigned an infinite value (denoted by<tt> ¯</tt> ).</p> <p>The utility of the notion of rank will now be illustrated briefly by introducing the <b>rank operator</b>, which yields a derived function of specified rank. Thus<tt> f⍤2 ¯1 1 </tt>yields a derived function of monadic rank<tt> 2</tt> ,<tt> </tt> of complementary left rank<tt> 1</tt> ,<tt> </tt> and right rank <tt> 1</tt> .<tt> </tt> Moreover,<tt> f⍤r ←→ f⍤(⌽3⌽⍴⌽r)</tt> ,<tt> </tt> so that abbreviated forms such as<tt> f⍤2 </tt> (all ranks are<tt> 2</tt> ),<tt> </tt>and<tt> f⍤2 3 </tt> (left rank is 2 and both right ranks are<tt> 3</tt> )<tt> </tt> may be used. For example,<tt> ,⍤2⍵ </tt>ravels the last two axes of the argument,<tt> ,⍤¯2⍵ </tt>ravels all but the first two, and<tt> ,⍤0⍵ </tt>adds a final unit axis to the axes of the argument.</p> <p>A necessary first step in establishing the use of ranks is to define the ranks of all existing functions. Because of the treatment of degenerate cases, it is possible to do this in a manner compatible with existing definitions by simply assigning infinite ranks to all. However, it is generally more useful to assign the lowest rank which will ensure compatibility with existing definitions, since this leads to simpler definitions of the functions, and greater utilization of the general scheme of extension. In particular, the scalar functions can, and will, be assigned rank<tt> 0</tt> .</p> <p>The argument for assigning to a function<tt> f </tt> the lowest compatible rank is somewhat weakened by the fact that a corresponding function of lower rank<tt> r </tt> is so easily obtained from the expression<tt> f⍤r</tt> .<tt> </tt> Thus, although<tt> ⌽ </tt>could be assigned monadic rank<tt> 1</tt> ,<tt> </tt> it might instead be assigned infinite rank, so as not to make it dissimilar to<tt> ⊖</tt> ,<tt> </tt> which must be assigned infinite monadic rank.</p> <p><a href="RationalizedAPL1.htm#xa">Appendix A</a> shows a table of the proposed rank assignments, together with notes on the less obvious choices. The scalar functions are not included in the table.</p> <a name="f2"></a> <p><b>Conformance.</b> In the application of a dyadic function<tt> f</tt> ,<tt> </tt> the outer shapes<tt> ol </tt>and<tt> or </tt> are each split into two sets of axes (called <b>bound</b> and <b>free</b>) such that<tt> ol=bl,fl </tt>and<tt> or=br,fr</tt> ;<tt> </tt> the shape of the overall result is<tt> b,fl,fr,sir</tt> ,<tt> </tt> where<tt> b </tt>is one of<tt> bl </tt> and<tt> br</tt> ,<tt> </tt>and<tt> sir </tt> is the shape of the individual results of applying the function to its cells.</p> <p>A shape<tt> s </tt>is said to be <b>single</b> if<tt> 1=×/s</tt> ;<tt> </tt>if <b>one</b> of<tt> bl </tt>and<tt> br </tt> is single, then<tt> b </tt>equals the other; if both are, then<tt> b </tt>equals the one of greater length; if neither is single, then<tt> bl </tt>and<tt> br </tt>must agree, and<tt> b </tt>is chosen as either one.</p> <p>The number of bound axes (that is, the lengths of<tt> bl </tt>and of<tt> br</tt> )<tt> </tt> is limited by the <b>conformance</b> of the function<tt> f</tt> ;<tt> </tt> all primitive functions have infinite conformance, and the <b>conformance operator</b>, denoted by<tt> f.k </tt> (where<tt> k </tt>is a non-negative integer), produces a derived function equivalent to<tt> f </tt> but having conformance<tt> k</tt> .<tt> </tt>For example:</p> <pre> ⍴(a←2 3 4⍴⍳24)×. 0(b←2 3 5⍴⍳30) 2 3 4 2 3 5 ⍴a ×. 1 b 2 3 4 3 5 ⍴a ×. 2 b 2 3 4 5 ⍴a ×. 3 b length error ⍴a×. 1 (1 1 4⍴9) 2 3 4 ⍴a×. 2 (3 4⍴9) 2 3 4 ⍴(1 1 1⍴8)+1 1⍴9) 1 1 1 </pre> <p>The case of zero conformance<tt> </tt>( <tt>f. 0</tt> )<tt> </tt> is equivalent to outer product<tt> </tt>( <tt>∘.f</tt> ).<tt> </tt> Except for the conformance operator itself, every operator produces derived functions having infinite conformance.</p> <p>If<tt> 1=×/s</tt> ,<tt> </tt>then the shape<tt> s </tt> is said to be (the shape of) a <b>singleton</b>. Singleton bound shapes are given special treatment that formalizes, and extends to non-scalar functions, the use of scalar and other singleton arguments in expressions such as<tt> 2 3 + 4 </tt> and<tt> 2 3 + ,4 </tt> and<tt> 2 3 + 1 1 1 1⍴4</tt> .<tt> </tt> Thus, if <b>one</b> of<tt> bl </tt>and<tt> br </tt>is a singleton, conformance is satisfied and the bound part of the shape of the result is determined by the other; if both are singletons, then the bound part of the shape is determined by the one of larger rank. For example,<tt> ⍴(1 1 1⍴4)+1 1⍴2 </tt> is<tt> 1 1 1</tt> .</p> <br><a name="g"></a> <p><b>G. Operators and Nonscalar Functions</b> <p>The reduction operator can, as remarked in the introduction, be consistently extended to non-scalar functions in at least two different ways, and similar variety is possible for the remaining conventional operators. We will now present a systematic scheme of extension (based upon the notion of function rank) which applies to all of the existing operators except the (bracket) axis operator. This operator is excluded because of its anomalous syntax, and because its purpose can be conveniently served by the rank operator, sometimes in conjunction with the transpose operator.</p> <p>The cases of reduction are straightforward:<tt> f⌿⍵ </tt>splits the argument<tt> ⍵ </tt> along the leading axis and applies<tt> f </tt>between the resulting subarrays;<tt> f/⍵ </tt> splits along the final axis.</p> <p>The outer and inner products are conveniently defined in terms of conformance:</p> <pre> ⍺ ∘.g ⍵ ←→ ⍺ g. 0 ⍵ ⍺ f.g ⍵ ←→ f⌿(¯1⍥⊢⍺)g. 1 ⍵ </pre> <p>(The transpose operator<tt> ⍥ </tt>is fully defined in <a href="RationalizedAPL1.htm#k">Section K</a>; the effect of<tt> ¯1⍥⊢⍺ </tt>used above is to move the last axis of<tt> ⍺ </tt>to the leading position). The left and right ranks of the derived inner product are infinite.</p> <p>A notable result of this definition of inner product is that, (because of the permissive treatment of the conformance of singletons) the conventional permissive definition of inner product is preserved. For example, if<tt> 3 2 4≡⍴a</tt> and<tt> 1 5 6≡⍴b</tt> ,<tt> </tt> then<tt> a f.g b ←→ a f.g 4 5 6⍴b </tt>.</p> <p>A scan applies reduction over each of a set of partitions of one axis of the argument, and the result therefore includes a <b>supernumerary</b> axis corresponding to this set. The scan<tt> f\⍵ </tt>partitions along the <b>last</b> axis, and places the supernumerary axis <b>last</b>, after the (necessarily common) shape of the individual reductions. The scan<tt> f⍀⍵ </tt>partitions along the <b>first</b> axis, and places the supernumerary axis <b>first</b>, before the common shape of the individual reductions. Supernumerary axes are discussed more fully in <a href="RationalizedAPL1.htm#k">Section K</a>.</p> <br><a name="h"></a> <p><b>H. Miscellaneous</b></p> <p>This section treats three matters, a rationalization of the jot<tt> </tt>(<tt>∘</tt>)<tt> </tt> used in the outer product and of the <b>type</b> attribute of an array used in expansion and overtake, and some illustrations of the assertion (made in <a href="RationalizedAPL1.htm#g">Section G</a>) that the rank operator can fulfill the functions of the anomalous bracket operator.</p> <a name="h1"></a> <p><b>The type attribute.</b> For most purposes an APL array<tt> a </tt> is completely determined by its shape (which can be obtained by applying the function<tt> ⍴</tt> )<tt> </tt> and by the value of each of its elements (which can be obtained by indexing), and the array incorporates no other attributes which determine the result of applying functions to it. However, conventional APL includes two functions, the <b>overtake</b><tt> </tt>(<tt>↑ </tt>with a sufficiently large left argument), and the derived function <b>expansion</b><tt> </tt>(<tt>u\</tt> ,<tt> </tt> where<tt> u </tt>is boolean) which do depend on an attribute associated with neither the value of an element nor the shape: if<tt> n←⍳0 </tt>and<tt> c←''</tt> ,<tt> </tt> then<tt> n </tt>and<tt> c </tt>agree in shape and differ in no element, but<tt> 0\n </tt>and<tt> 0\c </tt>produce different results<tt> </tt>(<tt>,0 </tt>and<tt> ,' '</tt>),<tt> </tt> as do<tt> 1↑n </tt>and<tt> 1↑c</tt> .</p> <p>This anomalous behaviour of overtake and expansion arose as follows: they are essentially “selection” functions, but they depend upon a parameter not explicitly specified by their arguments, namely, the <b>filler</b> quantity to be inserted in each of the “new positions” produced. Moreover the domain of the catenate function was limited to arguments of the same <b>class</b> (numeric or character) so as to preclude the introduction of heterogeneous arrays of mixed classes. Consequently, the filler could not be a fixed quantity, but had to be drawn from the same class as the argument of the overtake or expansion function.</p> <p>For any argument<tt> a </tt>that contains at least one element (i.e.,<tt> 1≤×/⍴a</tt> ),<tt> </tt> the filler can be determined from the class of any one of the elements, but for an empty array, no element can provide this information. The definition of overtake and expansion on empty arrays therefore required either the choice of a single filler for all, or the introduction of an attribute, usually referred to as the <b>type</b> of an empty array.</p> <p>In conventional APL, arguments for the convenience provided by the type attribute (in maintaining the class of an argument in expressions such as<tt> u\u/a </tt> [for<tt> 0=∨/u</tt> ]<tt> </tt> and<tt> k↑j↓a </tt>[for <tt>j≥⍴a</tt> ])<tt> </tt> won the day. Although compatibility requires that the type attribute be maintained to continue the present behaviour of expansion and overtake, it does not require any further extension of its use in the definition of new or existing functions and operators.</p> <p>There are two classes of argument against further extension of the use of the type attribute of empty arrays: the complexity of the rules required for extension, and the possibility of providing the same (or nearly the same, or greater) convenience aimed at in the design of conventional APL, by means not then available.</p> <p>Some of the complexity can be glimpsed from the following:</p> <table> <tr><td valign=top>1.</td><td> </td><td> The need for rules for the types resulting from the expressions<tt> '',⍳0 </tt> and<tt> (⍳0),''</tt> .</td></tr> <tr><td valign=top>2.</td><td> </td><td> The need for further type rules for any new classes that may be introduced, such as enclosed and heterogeneous [<acronym title="APL*PLUS Nested Array System (STSC, Inc., 1981)">2</acronym>, <acronym title="APL2 Language Manual (IBM Corporation, SB21 3015, June 1982)">3</acronym>].</td></tr> </table> <p>Further indications of the complexity can be seen in the rather extensive discussions of types and prototypes in APL systems [<acronym title="APL*PLUS Nested Array System (STSC, Inc., 1981)">2</acronym>, <acronym title="APL2 Language Manual (IBM Corporation, SB21 3015, June 1982)">3</acronym>].</p> <p>The introduction of dyadic cases for derived functions has made it easy to provide extra parameters, as in the merge produced by the expression<tt> b i¨{ a</tt> .<tt> </tt> Moreover, an associated dyadic case of compression as discussed in <a href="RationalizedAPL1.htm#k">Section K</a> provides for the specification of fillers for expansion. Not only would<tt> 0 u\ n </tt> and<tt> ' ' u\ c </tt>specify the normal fillers for vectors<tt> n </tt>and<tt> c </tt>(empty or not), but<tt> 1 u\ n </tt>and<tt> '*' u\ c </tt> would provide useful generalizations.</p> <p>Since <b>take</b> is a selection function, a dyadic case<tt> b j¨↑ a </tt>could be defined to provide a merge analogous to<tt> b j¨{ a</tt> .<tt> </tt> Moreover, the derived function<tt> ↑¨a </tt> (defined by<tt> ↑¨a i ←→ i↑a</tt> )<tt> </tt> could be provided by an associated dyadic case: thus<tt> i ↑¨a b </tt> would employ a filler specified by<tt> b</tt> .<tt> </tt> Since the “new positions” need not even form a rectangular array,<tt> b </tt> should be a scalar, that is, the right rank of<tt> ↑¨a </tt> would be<tt> 0</tt> .</p> <p>In conclusion:</p> <table> <tr><td valign=top>1.</td><td> </td><td> Expressions such as<tt> f u/⍵ </tt> and<tt> i {¨⍵ f </tt> should be introduced to permit convenient specification of a filler quantity<tt> f</tt> . </td></tr> <tr><td valign=top>2.</td><td> </td><td> For any non-empty argument, a suitable filler should be defined for any new class of argument introduced. The filler<tt> <'' </tt>(denoted by<tt> ∘</tt> )<tt> </tt> will be used for enclosed arrays. </td></tr> <tr><td valign=top>3.</td><td> </td><td> For empty arrays, compatibility requires the continuation of two distinct fillers, but no new fillers should be introduced. In particular, the result of<tt> 1↑0⍴<'a' </tt> should be defined as <b>zero</b>, with a view to eventually eliminating the type distinction and making <b>all</b> such fillers <b>zero</b>. </td></tr> </table> <a name="h2"></a> <p><b>The bracket axis operator.</b> The following remarks about the bracket axis operator are based upon unpublished suggestions by Arthur Whitney: <pre> +⍀⍤¯2⍵ ←→ +⍀[2]⍵ ←→ +\[2]⍵ ⊖⍤¯2⍵ ←→ ⊖[2]⍵ ←→ ⌽[2]⍵ ⍺,¨⍉⍤¯2⍵ ←→ ⍺,[2]⍵ ⍺,¨<⍤¯2⍵ ←→ ⍺,[1.5]⍵ </pre> <p>In the foregoing identities, 0-origin indexing is assumed, and the identities do not hold for all degenerate cases of catenation that involve arguments of differing ranks. The function<tt> ,¨⍉ </tt>catenates along the leading axis, and<tt> ,¨< </tt>produces lamination along a new leading axis. Note that lamination to introduce a new axis at any position can be achieved without the use of fractional indices.</p> <br><a name="i"></a> <p><b>I. New Operators</b></p> <p>This section treats only those new operators that will be used directly in the definition of new functions in <a href="RationalizedAPL1.htm#j">Section J</a>; others are deferred to <a href="RationalizedAPL1.htm#k">Section K</a>. To facilitate distinctions between the cases distinguished by argument types (function-function, function-variable, variable-function, and variable-variable), we will use the names<tt> f </tt>and<tt> g </tt> exclusively for functions.</p> <p>This section treats three dyadic operators (denoted by<tt> ⍤</tt> ,<tt> ⍥</tt> ,<tt> </tt>and<tt> ¨</tt> ,<tt> </tt> and called <b>on</b>, <b>upon</b>, and <b>with</b>), although the cases<tt> f¨i</tt> ,<tt> i¨f</tt> ,<tt> </tt> and,<tt> i¨j </tt> are deferred to <a href="RationalizedAPL1.htm#k">Section K</a>. It also treats the monadic operator<tt> ⊂</tt> ,<tt> </tt> called <b>con</b>.</p> <p>The monadic operator<tt> ⊂ </tt>is defined as follows:<tt> ⍺f⊂⍵ ←→ ⍵f⍺</tt> ,<tt> </tt> and the right and left ranks of<tt> f⊂ </tt> are therefore the left and right ranks of<tt> f</tt> .<tt> </tt> Moreover, the monadic case<tt> f⊂⍵ </tt> is the function inverse to<tt> f</tt> ;<tt> </tt> the definition of this inverse (including its rank) is an <b>attribute</b> of the function<tt> f</tt> ,<tt> </tt> that is, it is part of the definition of<tt> f</tt> .<tt> </tt> For example, the inverse of the scalar function<tt> * </tt> is the scalar function<tt> ⍟</tt> ,<tt> </tt> and the inverse of the infinite rank function<tt> < </tt>is the rank<tt> 0 </tt> function<tt> ></tt> .</p> <p>The name <b>con</b> (meaning <b>in opposition to</b>) is chosen to suggest both the function inversion of the monadic case, and the argument inversion of the dyadic case; the symbol<tt> ⊂ </tt>resembles the letter c, the initial letter of both con and commute.</p> <p>The composition<tt> f⍤g </tt>is defined as in <a href="RationalizedAPL1.htm#c">Section C</a>, with the added proviso that the composition is “close” in the sense defined in <acronym title="K.E. Iverson, Operators and Functions (IBM Corporation, RC7091, 1978)">[6]</acronym>. In terms of function rank, this proviso may be stated very simply by declaring that the three ranks of the derived function<tt> f⍤g </tt> each equal the monadic rank of<tt> g</tt> .</p> <p>The “dual”<tt> f¨g </tt>has the same ranks as<tt> f⍤g</tt> ,<tt> </tt> the definitions being<tt> (g⊂)f g⍵ </tt> and<tt> (g⊂)(g⍺)f g⍵</tt> </tt> .<tt> </tt> The derived function<tt> f⍥g </tt> has the same ranks as<tt> g</tt> .</p> <p>The cases<tt> f⍤i </tt>and<tt> f⍥i </tt> and<tt> i⍥f </tt>will be defined so that together they provide the facility provided by the axis operator defined in <acronym title="Robert Bernecky and Kenneth E. Iverson, Operators and Enclosed Arrays (I.P. Sharp, Proceedings of the User Meeting, 1980)"> Reference 4</acronym>, but in a simpler and more flexible manner.</p> <p>The case<tt> f⍤i </tt>was defined in <a href="RationalizedAPL1.htm#f">Section F</a>, where it was referred to as the <b>rank</b> operator. The case<tt> f⍥i⍵ </tt>applies<tt> f </tt> to a transpose of<tt> ⍵ </tt> that moves axes<tt> i </tt>to the tail end. For example, if<tt> ⍴⍵ </tt> is<tt> 3 4 5 6 7</tt> ,<tt> </tt> then<tt> ⍴⊢⍤2 1⍵ </tt> is<tt> 3 6 7 5 4</tt> ,<tt> </tt> and<tt> ⍴⊢⍤0⍵ </tt> is<tt> 4 5 6 7 3</tt> . (The identity function<tt> ⊢ </tt>is defined in <a href="RationalizedAPL1.htm#j">Section J</a>.)</p> <p>In the general case, the right argument of<tt> ⍥ </tt>has three elements, one to specify the transpose to be applied to each of the argument cases: monadic, left, and right. Each is enclosed, and a simple or abbreviated argument is extended as follows:<tt> f⍥i ←→ f⍥(⌽3⍴⌽⊃i)</tt> .<tt> </tt> Negative indexing of <b>axes</b> can be used, as, for example, in<tt> ⊢⍤¯2⍵ </tt>to interchange the last two axes.</p> <p>The case<tt> i⍥f </tt>is defined similarly, except that the indicated axes are moved to the front. In conjunction with the identity function, the operator<tt> ⍥ </tt>can, as illustrated above, provide transpositions that would be much more awkward to write using the transpose function<tt> ⍉</tt> .</p> <p>Derived functions produced by the function definition operator<tt> ∇ </tt> are defined to have infinite rank.</p> <br><a name="j"></a> <p><b>J. New Functions</b></p> <p>This section defines a number of new functions, most of which have been proposed in earlier papers. The main point is to illustrate the ease of definition provided by the joint use of direct definition and rank specification. The symbol<tt> ¯ </tt>is used to denote infinity:</p> <table> <tr><td valign=top><b>Name</b></td><td valign=top><b>Symbol</b></td> <td><b> Definition</b></td> <tr><td valign=top>Dex </td><td valign=top align=center><tt>⊢</tt></td> <td><tt>'⍵'∇'⍵'</tt></td></tr> <tr><td valign=top>Lev </td><td valign=top align=center><tt>⊣</tt></td> <td><tt>''∇'⍺'</tt></td></tr> <tr><td valign=top>Nub/Cup </td><td valign=top align=center><tt>∪</tt></td> <td><tt>'((⍵⍳⍵)=⍳⍴⍵)/⍵←,⍵'∇'⍺,⍵' ⍤ ¯ 1 1</tt></td></tr> <tr><td valign=top>Member </td><td valign=top align=center><tt>∊</tt></td> <td><tt>'(∪⍵)∘.(∆⍤0)⍵'∇'∨/⍺≡⍤0,⍵' ⍤ ¯ 0 ¯</tt></td></tr> <tr><td valign=top>Onub/Cap</td><td valign=top align=center><tt>∩</tt></td> <td><tt>'(,⍤0⍋∪⍵){∪⍵'∇'(⍺∊⍵)/⍺' ⍤ ¯ 1 1</tt></td></tr> <tr><td valign=top>Not </td><td valign=top align=center><tt>~</tt></td> <td><tt>'1-⍵'∇'(∆⍺∊⍵)/⍵' ⍤ 0 1 1</tt></td></tr> <tr><td valign=top>CP/From </td><td valign=top align=center><tt>{</tt></td> <td><tt>m←'>∘.(,⍤0 1)¨>/(<⍤>⍵),∘' d←'>(⍳0)⍴⍤1(s⊥⍤1(s←n↑⍴⍵)|⍤1∆⍺)⌽⍤0 1<br> ,<⍤((⍴⍴⍵)-n←⍴,⍺)⍵'<br> m∇d⍤1 1 ¯ </tt></td></tr> </table> <p>The monadic case defined for<tt> ∊ </tt>is the <b>distribution</b> function defined in <acronym title="K.E. Iverson, Operators and Functions (IBM Corporation, RC7091, 1978)">[6]</acronym>; the function<tt> ≡ </tt>used in its definition is defined in <acronym title="K.E. Iverson, APL Syntax and Semantics (ACM, APL83)">[5]</acronym>, and yields a<tt> 1 </tt>if its arguments agree. The dyadic case of<tt> ~ </tt>is the set difference function.</p> <p>The monadic case of<tt> { </tt>is the <b>Cartesian</b> product over the enclosed elements of its argument, and yields a result whose shape is the catenation of the shapes of<tt> (⍴¨>⍵),<⍴⍵</tt> .<tt> </tt> For example:</p> <pre> { 1 2 ⊃ 3 4 ⊃ 5 1 3 5 1 4 5 2 3 5 2 4 5 </pre> <p>The self-reference<tt> </tt>(<tt>∆</tt>)<tt> </tt>in the definition of the dyadic case is used to define the from function discussed in <a href="RationalizedAPL1.htm#a">Section A</a>; except for the complementary indexing provided by the use of doubly enclosed elements, this definition is complete.</p> <br><a name="k"></a> <p><b>K. Further Operators</b></p> <p>The operators discussed in this section are not essential to the rationalization program for existing functions and operators carried out in Sections A-H. They do, however, constitute important extensions, and introduce one further notion, the placement of “supernumerary” axes produced in scans and similar “partitionings” along an axis. They also help to illuminate the mnemonic schemes employed in the choice of operator symbols and in the disposition of operator arguments.</p> <p>Because of the large number of functions required in a language, the adoption of mnemonic schemes (such as the use of a single symbol for related monadic and dyadic cases, for application to arrays of any rank and class, real or complex, as well as the use of a single operator with existing functions to obtain sums, products and maxima over arrays) can be an important aid to the user. Because a large number of operators will also be required, care should also be exercised in assigning symbols to them.</p> <p>Since each argument of a dyadic operator may belong to either of two classes (function or variable), and since each derived function produced is ambivalent, each operator symbol can produce as many as eight classes of functions; various kinds of similarities can be employed to group these functions in mnemonically useful ways.</p> <p>For example, the symbol<tt> ⍤ </tt>is called <b>on</b>, and the first entry in <a href="RationalizedAPL1.htm#xb">Appendix B</a> shows the use of different interpretations of the meaning of “on”: the case<tt> f⍤g </tt>is the application of<tt> f </tt>on the result of<tt> g </tt> (called <b>composition</b> in mathematics); the case<tt> f⍤i </tt>is the application of<tt> f </tt> on each of the pieces obtained by splitting the argument into subarrays of ranks determined by<tt> i</tt> ;<tt> </tt> the case<tt> i⍤f </tt>is the application of<tt> f </tt> on pieces obtained by splitting the argument <b>along</b> an axis or axes in a manner determined by<tt> i</tt> <tt> </tt> and<tt> i⍤j </tt>is the <b>constant function</b> whose value is<tt> i</tt> ,<tt> </tt> applied on subarrays of ranks determined by<tt> j</tt> .</p> <p>In cases such as<tt> f⍤i </tt> and<tt> i⍤f</tt> ,<tt> </tt> it is preferable to assign<tt> f⍤i </tt> to the more commonly used case, because<tt> f </tt> itself will often be a derived function, and an expression such as<tt> i⍤(+.×) </tt> requires parentheses, whereas<tt> +.×⍤i </tt>does not.</p> <p>The symbol<tt> ⍥ </tt>in the second entry of <a href="RationalizedAPL1.htm#xb">Appendix B</a> is called upon: the case<tt> f⍥g </tt>denotes application of the monadic function<tt> f </tt> upon the result of the dyadic function<tt> g</tt> ,<tt> </tt> the larger circle (as compared to<tt> ⍤</tt> ),<tt> </tt> indicating the larger valence in the application of<tt> g</tt> ;<tt> </tt> the cases<tt> f⍥i </tt>and<tt> i⍥f </tt> concern the application of<tt> f </tt> upon the result of a transpose (a function that also employs<tt> ○ </tt>in its symbol), the transpose moving the axes designated by<tt> i </tt>to the front if<tt> i </tt> precedes the operator, and to the back if it follows.</p> <p>Some of the relations among the cases of the operator denoted by the dot can be appreciated only by understanding that the inner product<tt> f.g </tt>is (except for a transposition of the left argument) a very special case of <b>tensor contraction</b> produced by combined use of the monadic and dyadic cases of the form<tt> f.i</tt> ,<tt> </tt> as in<tt> +. 2 ⍺ ×. 2 ⍵</tt> ,<tt> </tt> which “runs together” the first two axes of<tt> ⍺ </tt>and<tt> ⍵ </tt> (forming an outer product between the rest), and then applies<tt> + </tt>reduction over axis<tt> 1 </tt>and axis<tt> 0</tt> ,<tt> </tt> in that order. The equivalence of<tt> f. 0 </tt>and<tt> ∘.f </tt> has already been remarked. For example:</p> <pre> r←(2 3 4⍴⍳24)×. 2(2 3 5⍴⍳30) ⍴r 2 3 4 5 -. 2 r ¯300 ¯312 ¯324 ¯336 ¯348 ¯315 ¯327 ¯339 ¯351 ¯363 ¯330 ¯342 ¯354 ¯366 ¯378 ¯345 ¯357 ¯369 ¯381 ¯393 -⌿-⌿⍤¯1 r ¯300 ¯312 ¯324 ¯336 ¯348 ¯315 ¯327 ¯339 ¯351 ¯363 ¯330 ¯342 ¯354 ¯366 ¯378 ¯345 ¯357 ¯369 ¯381 ¯393 </pre> <a name="k1"></a> <p><b>Til.</b> <a href="RationalizedAPL1.htm#xb">Appendix B</a> shows two cases for the <b>til</b> operator, denoted by<tt> }</tt> .<tt> </tt> The case<tt> f}i ⍵ </tt>is the<tt> i</tt>th power of<tt> f</tt> ,<tt> </tt> and<tt> f}(-j) ←→ f⊂}j</tt> ,<tt> </tt> so that negative values of<tt> j </tt> give powers of the inverse function. Moreover, if<tt> i≥0</tt> ,<tt> </tt> then<tt> f}i </tt>has rank<tt> mf</tt> ;<tt> </tt> if<tt> i<0 </tt>it has the rank of the inverse function<tt> f⊂</tt> .</p> <p>The second case<tt> f}g </tt>has ranks<tt> mg</tt> ,<tt> rf</tt> ,<tt> </tt> and<tt> mg</tt> ,<tt> </tt> and is defined as follows:</p> <pre> ⍺ f}g ⍵ ←→ (g⍵)f⍺ f}g ⍵ ←→ (g⍵)f⍵ </pre> <p>As remarked in <acronym title="Arthur Whitney and Kenneth E. Iverson, Practical Uses of a Model of APL, (APL Quote Quad, Volume 13, Number 1, Proceedings of APL82, ACM, New York 1982)">[9]</acronym>, the case a<tt> f}g}h ⍵ </tt> is equivalent to<tt> (g⍵)f(h⍵) </tt> and is therefore very useful. It was also stated that<tt> ⍺f}⊢⍵ </tt> is equivalent to<tt> ⍺f⊂⍵</tt> ;<tt> </tt> although true in some instances, this is not true in general because the rank of the identity function<tt> ⊢ </tt> (which is infinite) may differ from the left rank of<tt> f</tt> .</p> <a name="k2"></a> <p><b>Dot.</b> In <a href="RationalizedAPL1.htm#f">Section F</a>, the dot operator, conventionally defined only for the case<tt> f.g</tt> ,<tt> </tt> was extended to the case<tt> f.k</tt> ,<tt> </tt> but only the dyadic case of the derived function was defined. The monadic case<tt> f.k ⍵ </tt> is defined as<tt> k </tt> successive reductions of the form<tt> f⌿⍤r</tt> .<tt> </tt> For example:<tt> f. 3 ⍵ ←→ f⌿ f⌿⍤¯1 f⌿⍤¯2 ⍵</tt> .<tt> </tt> It should be noted that this definition ensures that the reduction must take place over the<tt> k </tt>successive axes, whereas any one of a succession of reductions of the form<tt> f/⍥0 f/⍥1 f/⍥2 </tt> might (because of the characteristics of the arbitrary function<tt> f</tt> )<tt> </tt> entirely change all axes of its argument.</p> <p>As noted earlier, the monadic and dyadic cases of<tt> f.k </tt> together provide the contraction used in tensor analysis.</p> <a name="k3"></a> <p><b>Supernumerary axes.</b> Certain operators produce derived functions that may introduce one or more <b>supernumerary</b> axes in addition to the axes produced by the particular function to which the particular operator is applied. These supernumerary axes may be defined either to precede or follow the normal result axes of the function, the whole collection following, of course, the outer axes of the argument to which the derived function is applied.</p> <p>For example, scan introduces one extra axis contributed by applying reduction to each of a set of partitions of the argument, and a general derivative operator applied to a function of rank<tt> r </tt> introduces<tt> r </tt>extra axes (for differentiation with respect to each element of the argument).</p> <a name="k4"></a> <p><b>Scan.</b> Each scan operator behaves like the corresponding reduction operator, and places the supernumerary axis first if the split (in the reduction) is along the first axis, and last if the split is along the last axis. This definition provides conformity with conventional APL.</p> <a name="k5"></a> <p><b>Cut Operator.</b> With an integer left argument<tt> k</tt> ,<tt> </tt> the operator<tt> ⍤ </tt>provides a family of derived functions such that<tt> k⍤f </tt>applies<tt> f </tt>to pieces cut from its right argument, the pieces being determined by the left argument or, in the monadic case, by the right argument itself. The right ranks of all cases are infinite.</p> <p>There are seven cases:<tt> k=0 </tt> provides the general case, in terms of which each of the others can be expressed rather easily. Its left rank is<tt> 2</tt> ,<tt> </tt>and<tt> f </tt> is applied to a rectangle of size<tt> |1{⍺ </tt> beginning at<tt> 0{⍺ </tt>or, more precisely, to the rectangle<tt> r </tt>selected as follows:</p> <pre> r←((((¯1↑⍴⍺)↑⍴⍵)|0{⍺)+¨>⍳¨>|1{⍺){⍵ </pre> <p>Before applying<tt> f</tt> ,<tt> </tt>the piece<tt> r </tt>is reversed along each axis for which the specified size (that is,<tt> 1{⍺</tt> )<tt> </tt>is negative.</p> <p>Note that both negative and abbreviated indexing may be used in<tt> 0{⍺ </tt> to specify the position of the selected rectangle, and that reversals may be specified by negative elements in<tt> 1{⍺</tt> .</p> <p>The degenerate case of a vector left argument<tt> ⍺ </tt> is treated as<tt> ⍉0,⍤0⍺</tt> ,<tt> </tt> so as to select a piece of size<tt> ⍺ </tt> beginning at the origin. The monadic case<tt> 0⍤f ⍵ </tt>is equivalent to<tt> (⍴⍴⍵)⍴⌊/⍴⍵)0⍤f ⍵</tt> ,<tt> </tt> that is, it selects the “maximal cube” from<tt> ⍵</tt> .</p> <p>The cases<tt> ⍺ 1⍤f ⍵ </tt>and<tt> ⍺ ¯1⍤f ⍵ </tt> both apply<tt> f </tt>to pieces obtained by splitting<tt> ⍵</tt> ,<tt> </tt> along the leading axis, into segments <b>beginning</b> at each<tt> 1 </tt> in the boolean vector left argument<tt> ⍺</tt> ,<tt> </tt> the element at each cutpoint being included in the case of<tt> 1⍤f</tt> ,<tt> </tt>and excluded in the case<tt> ¯1⍤f</tt> .<tt> </tt> The supernumerary axis introduced is placed before the individual results. A “short” left argument<tt> ⍺ </tt> is extended cyclically by<tt> (1↑⍴⍵)⍴⍺</tt> .</p> <p>The left ranks of the functions<tt> 1⍤f </tt>and<tt> ¯1⍤f </tt> are<tt> 1</tt> ,<tt> </tt>and extension to higher ranks is made in the usual way. The monadic cases are equivalent to the dyadics with a left argument of<tt> (0{⍵)≡⍤¯ ¯1 ⍵</tt> ,<tt> </tt> that is, splits begin at occurrences of the “delimiter” specified by the leading subarray of<tt> ⍵</tt> .</p> <p>The cases<tt> 2⍤f </tt>and<tt> ¯2⍤f </tt>differ from the foregoing only in that each<tt> 1 </tt> in the left argument determines the <b>end</b> of a segment, and that the delimiter in the monadic case is the <b>last</b> subarray of<tt> ⍵</tt> ,<tt> </tt> namely,<tt> ¯1{⍵</tt> .</p> <p>The remaining cases,<tt> 3⍤f </tt> and<tt> ¯3⍤f</tt> ,<tt> </tt> provide (possibly overlapping) tessellations. The left rank is<tt> 2</tt> ,<tt> </tt> and the expression<tt> ⍺ ¯3⍤f ⍵ </tt>applies<tt> f </tt> to each <b>complete</b> rectangle of size<tt> |1{⍺ </tt>obtained by beginning at all positions obtained as integer multiples of (each element of) the <b>movement</b> vector<tt> 0{⍺</tt> .<tt> </tt> As in the case<tt> O⍤f</tt> ,<tt> </tt> reversal of each piece occurs along the axis for which the “window”<tt> 1{⍺ </tt>is negative.</p> <p>The degenerate case of a vector<tt> ⍺ </tt> is equivalent to the left argument<tt> ⍉1,⍤0⍺</tt> ,<tt> </tt> and therefore provides a complete tessellation of size<tt> ⍺</tt> .<tt> </tt> The monadic case provides tessellation by “maximal cubes” having the size<tt> (⍴⍴⍵)⍴⌊/⍴⍵</tt> .</p> <p>The case<tt> 3⍤f </tt>differs from<tt> ¯3⍤f </tt> only in that any “shards” of sizes less than<tt> |1{⍺ </tt>are included.</p> <a name="k6"></a> <p><b>With.</b> If the ranks of the arguments<tt> i </tt> and<tt> j </tt>in the expressions<tt> i¨f ⍵ </tt> and<tt> f¨j ⍵ </tt>are equal to the left and right ranks of<tt> f</tt> ,<tt> </tt> then the definitions are straightforward:</p> <pre> i¨f ⍵ ←→ i f ⍵ f¨j ⍵ ←→ ⍵ f j </pre> <p>However, arguments<tt> i </tt>and<tt> j </tt> of greater rank introduce axes which are placed before the individual results. Consequently, the derived functions behave more like outer products of<tt> f </tt> than like direct applications of<tt> f</tt> .<tt> </tt> For example, if<tt> a←1 2 3</tt> ,<tt> </tt> then<tt> a¨+a ←→ a∘.+a</tt> .</p> <a name="k7"></a> <p><b>Compression.</b> The definitions of the derived functions<tt> i/ </tt>and<tt> i⌿ </tt> (called <b>compression</b> or <b>replication</b>) are based upon a vector argument<tt> i</tt> .<tt> </tt> The effect of<tt> i⌿⍵ </tt>is to split<tt> ⍵ </tt> along its <b>first</b> axis, select subarrays determined by<tt> i</tt> ,<tt> </tt> and array them along a supernumerary axis that is placed <b>first</b>; the effect of<tt> i/⍵ </tt> is to split along the <b>last</b> axis and to place the supernumerary axis <b>last</b>.</p> <p>An argument<tt> i </tt>of rank greater than<tt> 1 </tt> will introduce further axes that are placed <b>first</b> in both<tt> i/⍵ </tt>and<tt> i⌿⍵</tt> .<tt> </tt> Dyadic cases of<tt> i/ </tt>and<tt> i⌿ </tt> should also be defined, with negative values in<tt> i </tt>providing selection from the left argument <acronym title="APL2 Introduction Manual (IBM Corporation, SB21 3039, June 1982)">[10]</acronym>.</p> <br><a name="l"></a> <p><b>L. Summary</b></p> <p>The proposals essential to the rationalization program described in the introduction can be summarized as follows:</p> <table> <tr><td valign=top>1.</td><td> </td><td> The enclose function<tt> < </tt>provides lists which are used as arguments to a normal indexing function (<tt>{</tt> ,<tt> </tt>called <b>from</b>) to provide “scattered”, “complementary”, “abbreviated”, and “negative” indexing, as well as all of the facilities provided by conventional indexing. The dyadic case of<tt> i¨{ </tt>provides a merge that obviates indexed assignment. <br> </td></tr> <tr><td valign=top>2.</td><td> </td><td> The extension of<tt> ← </tt>to allow any APL entity to its right provides convenient name assignment for functions and operators as well as variables. <br> </td></tr> <tr><td valign=top>3.</td><td> </td><td> The definition operator<tt> ∇ </tt>provides convenient definition of independent monadic and dyadic cases of functions. <br> </td></tr> <tr><td valign=top>4.</td><td> </td><td> The syntax rules are extended to operators (to give them “long left scope”) by a table shown in <a href="RationalizedAPL1.htm#e">Section E</a>. The recognition of cases, and the corresponding evaluations, involve only the first four elements of the execution stack. <br> </td></tr> <tr><td valign=top>5.</td><td> </td><td> <p>A uniform scheme for extending functions to higher-rank arrays is provided by assigning to each function<tt> f </tt>four primary attributes that determine its application to any arguments: a monadic rank<tt> mf</tt> ,<tt> </tt> a left rank<tt> lf</tt> ,<tt> </tt> a right rank<tt> rf</tt> ,<tt> </tt> and a conformance<tt> cf</tt> .</p> <p>In the normal case of arguments of sufficiently high rank, the function applies to the “low-order” subarrays of appropriate rank to produce individual results of a common shape<tt> sir</tt> ,<tt> </tt> the shape of the overall result of<tt> ⍺ f ⍵ </tt>being:</p> <p><tt> (cf↑⍴⍺),(cf↓(-lf)↓⍴⍺),(cf↓(-rf)↓⍴⍵),sir</tt></p> <p>The conformability imposed on the arguments is that<tt> cf↑⍴⍺ </tt>must equal<tt> cf↑⍴⍵</tt> ,<tt> </tt> or that at least one must be <b>single</b>, (i.e., having a shape<tt> s </tt> such that<tt> 1=×/s</tt> ).</p> </td></tr> </table> <br> <br><a name="xa"></a> <p><b>Appendix A. Ranks of Primitive Functions</b></p> <p>The following table shows the proposed ranks for all primitive APL functions except the scalar functions, whose ranks are all zero. The ranks are shown in the order monadic, left, and right, with an overbar denoting infinite rank. The indices in the left column refer to notes following the table. The notes employ<tt> aO </tt>and<tt> bO </tt>to denote scalars,<tt> a1 </tt>and<tt> b1 </tt>to denote vectors, etc.</p> <p>The proposed ranks were chosen in the light of the following general considerations:</p> <table> <tr><td valign=top>1.</td><td> </td><td> <b>Infinite</b>, or <b>unbounded</b> rank will always allow compatibility with existing definitions, since the <b>degenerate</b> cases (of arguments having rank less than the maximum imposed by the stated rank of the function) can be defined as desired. Wherever necessary, infinite rank is chosen. <br> </td></tr> <tr><td valign=top>2.</td><td> </td><td> The minimum possible rank is preferred because it allows the simplest definition of the function, the definition for arguments of higher rank following from the general extension rule. <br> </td></tr> <tr><td valign=top>3.</td><td> </td><td> Questions concerning the possibly differing shapes of individual results (which, for example, precluded the inclusion of dyadic query<tt> </tt>(<tt>?</tt>)<tt> </tt> among the scalar functions) are ignored because <b>close composition</b> can be used to produce individual results of a common shape. For example,<tt> a<⍥?b </tt>produces individual scalar results which are enclosed vectors of (possibly) differing lengths. <br> </td></tr> <tr><td valign=top>4.</td><td> </td><td> Because of anomalies in its syntax and its definition, the “bracket axis operator” is not included among operators whose definitions depend upon the ranks of their function arguments. Consequently, the definitions of expressions involving the bracket operator are left strictly unchanged, and their behaviour does not figure in the choice of ranks made here. <br> </td></tr> <tr><td valign=top>5.</td><td> </td><td> Because of anomalies in its syntax and its definition, the “bracket indexing function” is not included among the functions to which operators apply, and no attempt will be made to define its rank. </td></tr> </table> <br> <table align=center><tr><td valign=top><table> <tr><td align=right>Note</td><td> </td><td align=right><tt>f</tt></td><td> </td> <td><tt>m</tt></td><td> </td><td><tt>l</tt></td><td> </td><td><tt>r</tt></td></tr> <tr><td> </td> <td> </td><td align=right><tt>< </tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>0</tt></td><td> </td><td><tt>0</tt></td></tr> <tr><td> </td> <td> </td><td align=right><tt>> </tt></td><td> </td><td><tt>0</tt></td><td> </td><td><tt>0</tt></td><td> </td><td><tt>0</tt></td></tr> <tr><td align=right>1</td> <td> </td><td align=right><tt>⍴ </tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>1</tt></td><td> </td><td><tt>¯</tt></td></tr> <tr><td align=right>2</td> <td> </td><td align=right><tt>, </tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>¯</tt></td></tr> <tr><td align=right>3</td> <td> </td><td align=right><tt>⌽ </tt></td><td> </td><td><tt>1</tt></td><td> </td><td><tt>1</tt></td><td> </td><td><tt>2</tt></td></tr> <tr><td> </td> <td> </td><td align=right><tt>⊖ </tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>¯</tt></td></tr> <tr><td align=right>4</td> <td> </td><td align=right><tt>⍉ </tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>1</tt></td><td> </td><td><tt>¯</tt></td></tr> <tr><td align=right>5</td> <td> </td><td align=right><tt>↑↓</tt></td><td> </td><td> </td> <td> </td><td><tt>1</tt></td><td> </td><td><tt>¯</tt></td></tr> <tr><td align=right>6</td> <td> </td><td align=right><tt>⍳ </tt></td><td> </td><td><tt>1</tt></td><td> </td><td><tt>1</tt></td><td> </td><td><tt>0</tt></td></tr> </table></td><td><tt> </tt></td><td valign=top><table> <tr><td align=right>Note</td><td> </td><td align=right><tt>f</tt></td><td> </td> <td><tt>m</tt></td><td> </td><td><tt>l</tt></td><td> </td><td><tt>r</tt></td></tr> <tr><td> </td> <td> </td><td align=right><tt>∊ </tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>0</tt></td><td> </td><td><tt>¯</tt></td></tr> <tr><td> </td> <td> </td><td align=right><tt>⍋⍒</tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>¯</tt></td></tr> <tr><td align=right>7</td> <td> </td><td align=right><tt>? </tt></td><td> </td><td><tt>0</tt></td><td> </td><td><tt>0</tt></td><td> </td><td><tt>0</tt></td></tr> <tr><td align=right>8</td> <td> </td><td align=right><tt>⌹ </tt></td><td> </td><td><tt>2</tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>2</tt></td></tr> <tr><td align=right>9</td> <td> </td><td align=right><tt>⊥ </tt></td><td> </td><td> </td> <td> </td><td><tt>1</tt></td><td> </td><td><tt>¯</tt></td></tr> <tr><td> </td> <td> </td><td align=right><tt>⊤ </tt></td><td> </td><td> </td> <td> </td><td><tt>¯</tt></td><td> </td><td><tt>¯</tt></td></tr> <tr><td align=right>10</td><td> </td><td align=right><tt>⍕ </tt></td><td> </td><td><tt>¯</tt></td><td> </td><td><tt>2</tt></td><td> </td><td><tt>1</tt></td></tr> <tr><td align=right>11</td><td> </td><td align=right><tt>⍎ </tt></td><td> </td><td><tt>1</tt></td><td> </td><td> </td> <td> </td><td> </td> </tr> <tr><td> </td> <td> </td><td align=right><tt>≡ </tt></td><td> </td><td> </td> <td> </td><td><tt>¯</tt></td><td> </td><td><tt>¯</tt></td></tr> </table></td></tr></table> <p align=center><b>Ranks of Primitive Functions<br>Table 1</b></p> <p><b>Notes</b></p> <table> <tr><td valign=top>1.</td><td> </td><td> The degenerate case<tt> a0⍴b </tt>is defined as in conventional APL. <br> </td></tr> <tr><td valign=top>2.</td><td> </td><td> Ranks<tt> 1 1 </tt>for dyadic could have been considered because they work for all cases of the form<tt> a2,b2 </tt> and<tt> a3,b3</tt> ,<tt> </tt> but they would not agree with the present definition of cases such as<tt> a2,b1 <tt>and<tt> a3,b2</tt> . <br> </td></tr> <tr><td valign=top>3.</td><td> </td><td> Ranks<tt> 0 1 </tt>for dyadic would be preferable, but would require a change in the present definition, since<tt> ((k⍴1)⍴s)⌽⍳n </tt>is now permitted, and yields a result of shape<tt> n </tt>rather than<tt> (kp1),n</tt> .<tt> </tt> Ranks<tt> 1 2 </tt>could provide compatibility with the most commonly used case of<tt> k=1</tt> .<tt> </tt> Either choice clearly shows the unit difference in rank required of arguments to the function. <br> </td></tr> <tr><td valign=top>4.</td><td> </td><td> The degenerate case<tt> a0⍉bk </tt> will remain as it is. <br> </td></tr> <tr><td valign=top>5.</td><td> </td><td> The degenerate cases<tt> a0↓b1 </tt>and<tt> a0↑b1 </tt> will remain as in conventional APL. <br> </td></tr> <tr><td valign=top>6.</td><td> </td><td> <p>Rank<tt> 0 </tt>for the monadic case would introduce an unmanageable anomaly in the present permissive treatment of the case<tt> ⍳a1←,a0 </tt> since the result would necessarily have an outer shape of<tt> 1</tt> .</p> <p>Moreover, rank<tt> 1 </tt>would allow (or even suggest) the extension to the “odometer” function such that<tt> ⍳a1 </tt>yields a result of shape<tt> a1,⍴a1 </tt> containing (along its last axis) all indices of an array of shape<tt> a1</tt> .<tt> </tt> The present anomalous treatment of the case where<tt> ⍴a1 </tt>is<tt> 1 </tt> could be maintained.</p> <p>For the dyadic case, the ranks<tt> ¯ 0 </tt> would allow the production of vector indices to an array of any rank. For example,<tt> (3 3⍴⍳9)⍳2 3 4 </tt> would (in<tt> 0</tt>-origin) produce the matrix<tt> 3 2⍴0 2 1 0 1 1</tt> .<tt> </tt> However, this would imply that the indices to a vector should produce an array of one-element vectors, and that the shape of<tt> a1⍳ak </tt> would be<tt> (⍴ak),1 </tt> rather than<tt> ⍴ak </tt>as it now is. Compatibility could, of course, be obtained by treating a vector left argument as a special degenerate case.<br> </p> </td></tr> <tr><td valign=top>7.</td><td> </td><td> <p>Rank<tt> 0 0 </tt>is preferred for the dyadic case, but may be precluded by the permissive use of one-element vector arguments, since it would make the cases<tt> a0?b1</tt> ,<tt> a1?b0</tt> ,<tt> </tt> and<tt> a1?b1 </tt> differ from<tt> a0?b0 </tt>by an added<tt> 1 </tt> in the shape vector. However, it is possible that the use of the deal function is as yet infrequent enough to permit the necessary change in its definition.</p> <p>The choice of rank<tt> 1 1 </tt>would make it possible to continue the present anomalies for degenerate cases. Although this choice makes the function less versatile, it should be noted that the “correct” behaviour would be easily obtained in the derived function<tt> ?⍤0</tt> .<br> </p> </td></tr> <tr><td valign=top>8.</td><td> </td><td> Since<tt> a2⌹b2 ←→ (⌹b2)+.×a2</tt> ,<tt> </tt> the result is a collection of results for the columns of<tt> a2</tt> ,<tt> </tt> and a left rank of<tt> 1 </tt>cannot, therefore, be compatible with the conventional definition. <br> </td></tr> <tr><td valign=top>9.</td><td> </td><td> Because<tt> ⊥ </tt>applies to vectors along the leading (rather than the trailing) axis of the right argument, a bounded right rank cannot give compatible results. <br> </td></tr> <tr><td valign=top>10.</td><td> </td><td> A left rank of<tt> 2 </tt>will accomodate a matrix whose two columns specify decimal point and width. The degenerate vector case would be treated as in conventional APL. <br> </td></tr> <tr><td valign=top>11.</td><td> </td><td> Treating execute as a normal function of rank<tt> 1 </tt>could be very useful. For example, if<tt> a2 </tt>is numeric, then<tt> ⍎b2←⍕a2 </tt>would yield<tt> a2</tt> .<tt> </tt> However, since the arguments of<tt> ⍎ </tt>may be expressions which produce side-effects, and since the order of applying any function to its cells is not prescribed, the results could be unpredictable. Similar remarks apply to the function<tt> ? </tt> because of the side-effect produced by the re-specification of<tt> ⎕rl</tt> . <br> </td></tr> </table> <br><a name="xb"></a> <p><b>Appendix B. Table of Dyadic Operators</b></p> <p>The following conventions are used:</p> <p><tt>i </tt>and<tt> j </tt>denote variables, and<tt> f </tt>and<tt> g </tt>functions.</p> <p><tt>mf</tt> ,<tt> lf</tt> ,<tt> </tt> and<tt> rf </tt>denote monadic, left, and right ranks of<tt> f </tt>and<tt> af </tt> denotes all ranks of<tt> f</tt>.</p> <p>The monadic derived function is shown to the left of the dyadic.</p> <table> <tr><td> </td><td> </td><td><tt> j g</td></tr> <tr><td rowspan=2 valign=top width=60><tt>⍤</tt><br>On</td><td><tt>i</tt></td> <td rowspan=2> <table border=1 cellspacing=0 cellpadding=5> <tr><td valign=top align=center width=130>Constant<tt> i </tt>on<br><tt> j </tt>cells</td> <td width=260><table> <tr><td colspan=5 align=center>Cuts</td></tr> <tr><td>Cube</td><td> </td><td><tt> 0</tt></td> <td> </td><td>General</td></tr> <tr><td>Begin at<tt> 0{⍵</tt></td><td> </td><td><tt>1 ¯1</tt></td> <td> </td><td>Begin at<tt> 1</tt>’s</td></tr> <tr><td>End at <tt> ¯1{⍵</tt></td><td> </td><td><tt>2 ¯2</tt></td> <td> </td><td>End at<tt> 1</tt>’s</td></tr> <tr><td>Cubic</td><td> </td><td><tt>3 ¯3</tt></td> <td> </td><td>Tesselation</td></tr> <tr><td colspan=5 align=center>Include shards or cutpoints<br> if<tt> i </tt>is positive</td></tr> </table></td></tr> <tr><td valign=top align=center><tt>f </tt>on rank<tt> j </tt> <br>cells</td> <td><table align=center> <tr><td align=center width=120><tt>f g ⍵ </tt></td><td>|</td><td align=center width=120><tt>(g⍺)f(g⍵)</tt></td></tr> <tr><td align=center width=120> </td> <td>|</td><td align=center width=120> </td></tr> <tr><td colspan=3 align=center>Ranks are<tt> mg</tt></td></tr> </table></td></tr> </table></td></tr> <tr><td><tt>f</tt></td></tr> </table> <br> <table> <tr><td> </td><td> </td><td><tt> j g</td></tr> <tr><td rowspan=2 valign=top width=60><tt>⍥</tt><br>Upon</td><td> <br><tt>i</tt></td> <td rowspan=2> <table border=1 cellspacing=0 cellpadding=5> <tr><td valign=top width=130> </td> <td align=center>Axis<tt> i </tt>to front and<br>apply<tt> g </tt></td></tr> <tr><td valign=top align=center>Axis<tt> j </tt>to rear and<br>apply<tt> f </tt></td> <td width=260><table align=center> <tr><td align=center width=120><tt>f g ⍵ </tt></td><td>|</td><td align=center width=120><tt>f ⍺ g ⍵</tt></td></tr> <tr><td align=center width=120> </td> <td>|</td><td align=center width=120> </td></tr> <tr><td colspan=3 align=center>Ranks are<tt> ag</tt></td></tr> </table></td></tr> </table></td></tr> <tr><td><br> <br><tt>f</tt><br> <br> </td></tr> </table> <br> <table> <tr><td> </td><td> </td><td><tt> j g</td></tr> <tr><td rowspan=2 valign=top width=60><tt>¨</tt><br>With</td><td> <br><tt>i</tt></td> <td rowspan=2> <table border=1 cellspacing=0 cellpadding=5> <tr><td valign=top width=130> </td> <td><table align=center> <tr><td align=center width=120><tt>i g ⍵</tt></td> <td>|</td><td align=center width=120>Some special</td></tr> <tr><td align=center width=120>Rank is<tt> rg</tt></td><td>|</td><td align=center width=120>cases:<tt> i¨{</tt></td></tr> </table></td></tr> <tr><td><table align=center> <tr><td align=center><tt>⍵ f j </tt></td><td>|</td><td> </td></tr> <tr><td align=center> </td> <td>|</td><td> </td></tr> <tr><td colspan=3 align=center>Rank is<tt> lf </tt></td></tr> </table></td> <td width=260><table align=center> <tr><td align=center width=120><tt>(g⊂)f g ⍵</tt></td><td>|</td><td align=center width=120><tt>(g⊂)(g⍺)f g ⍵</tt></td></tr> <tr><td align=center width=120> </td> <td>|</td><td align=center width=120> </td></tr> <tr><td colspan=3 align=center>Rank is<tt> mg</tt></td></tr> </table></td></tr> </table></td></tr> <tr><td><br> <br><tt>f</tt><br> <br> </td></tr> </table> <br> <table> <tr><td> </td><td> </td><td><tt> j g</td></tr> <tr><td rowspan=2 valign=top width=60><tt>.</tt><br>Dot</td><td> <br><tt>i</tt></td> <td rowspan=2> <table border=1 cellspacing=0 cellpadding=5> <tr><td valign=top width=130> </td> <td><table align=center> <tr><td width=120> </td><td>|</td><td align=center width=120><tt>∘.g</tt></td></tr> </table></td></tr> <tr><td><table align=center> <tr><td align=center><tt>j</tt> Reductions:</td><td>|</td><td align=center>Conform-</td></tr> <tr><td align=center><tt>f⌿f⌿⍤1f⌿...</tt></td> <td>|</td><td align=center>ance<tt> j</tt></td></tr> </table></td> <td width=260><table align=center> <tr><td align=center width=120>Determinant</td><td>|</td><td align=center width=120>Inner</td></tr> <tr><td align=center width=120> </td> <td>|</td><td align=center width=120>Product</td></tr> </table></td></tr> </table></td></tr> <tr><td><br> <br><tt>f</tt><br> <br> </td></tr> </table> <br> <table> <tr><td> </td><td> </td><td><tt> j g</td></tr> <tr><td rowspan=2 valign=top width=60><tt>}</tt><br>Til</td><td> <br><tt>i</tt></td> <td rowspan=2> <table border=1 cellspacing=0 cellpadding=5> <tr><td valign=top width=130> </td><td> </td></tr> <tr><td><table align=center> <tr><td align=center><tt>j</tt>th power of<tt> f</tt></td><td>|</td><td> </td></tr> <tr><td align=center> </td> <td>|</td><td> </td></tr> <tr><td align=center> </td> <td>|</td><td> </td></tr> </table></td> <td width=260><table align=center> <tr><td align=center width=120><tt>(g⍵)f ⍵</tt></td><td>|</td><td align=center width=120><tt>(g⍵)f ⍺</tt></td></tr> <tr><td align=center width=120>rank<tt> mg</tt></td><td>|</td><td align=center width=120>right<tt> mg</tt></td></tr> <tr><td align=center width=120> </td> <td>|</td><td align=center width=120>left<tt> rf</tt></td></tr> </table></td></tr> </table></td></tr> <tr><td><br> <br><tt>f</tt><br> <br> </td></tr> </table> <br> <table> <tr><td> </td><td> </td><td><tt> j g</td></tr> <tr><td rowspan=2 valign=top width=60><tt>∇</tt><br>Del</td><td><tt>i</tt></td> <td rowspan=2> <table border=1 cellspacing=0 cellpadding=5> <tr><td align=center width=130>Direct Definition</td><td width=260> </td></tr> <tr><td align=center><tt>j</tt>th derivative</td><td> </td></tr> </table></td></tr> <tr><td><tt>f</tt></td></tr> </table> <br> <br><a name="xc"></a> <p><b>Appendix C. Examples and Brief Definitions</b></p> <p>This appendix provides loose definitions and numerous examples of use of the functions and operators defined more formally in the body of the paper. This appendix may be read first, although it is probably best to make concurrent reference to the body as desired. The ideas introduced in Sections B to E (<a href="RationalizedAPL1.htm#b">Name Assignment</a>, <a href="RationalizedAPL1.htm#c">Function Valence</a>, <a href="RationalizedAPL1.htm#d">Function Definition</a>, and <a href="RationalizedAPL1.htm#e">Syntax and Order of Execution</a>) will be treated only indirectly by using them in the discussion of other topics.</p> <p>The following functions will be used in examples:</p> <table> <tr><td valign=top>Enclose</td><td> </td> <td valign=top><tt><</tt> </td><td> </td> <td valign=top><tt>⍴⍴<a ←→ 0</tt> ,<tt> </tt> and<tt> ><a ←→ a</tt> ,<tt> </tt> and<tt> <a </tt>is called a <b>non-simple</b> array. <br> </td></tr> <tr><td valign=top>Disclose</td><td> </td> <td valign=top><tt>></tt> </td><td> </td> <td valign=top>Inverse of<tt> <</tt> ,<tt> </tt> but applies to each element of its argument. <br> </td></tr> <tr><td valign=top>Link</td><td> </td> <td valign=top><tt>⊃</tt> </td><td> </td> <td valign=top><table> <tr><td><tt>⊃⍵</tt> </td> <td> <tt>←→</tt> <td><tt><⍵ </tt>if<tt> ⍵ </tt>is simple</td></tr> <tr><td> </td> <td> <tt>←→</tt> <td><tt> ⍵ </tt>if<tt> ⍵ </tt>is non-simple</td></tr> <tr><td><tt>⍺⊃⍵</tt> </td><td> <tt>←→</tt> <td><tt>(<⍺),⊃⍵</tt> </td></tr> </table> </td></tr> </table> <p>The examples shown in this appendix were executed by the function<tt> apl </tt>in workspace<tt> 705 model</tt> .<tt> </tt> <tt>0</tt>-origin indexing is assumed thoughout, and infinity is denoted by the overbar<tt> ¯</tt> .</p> <a name="xc1"></a> <p><b>Function Ranks and Disposition of Axes</b></p> <p>Function rank is the most important notion needed to provide a simple and systematic basis for the uniform treatment of all “mixed” or non-scalar functions. It is also relatively difficult to grasp: although the rules for rank are simple, their consequences are neither obvious nor inconsequential, and the reader unfamiliar with function rank should carefully study the simple examples of its use, in preparation for the more complex and more rewarding uses in dyadic functions and in conjunction with operators such as composition and dual.</p> <p>If<tt> f </tt>has rank<tt> r</tt> ,<tt> </tt> then<tt> f⍵ </tt>is determined by applying<tt> f </tt> to each of the “cells” of shape<tt> (-r)↑⍴⍵</tt> ,<tt> </tt> producing a common shape<tt> s </tt>for each, and assembling the whole into a result of shape<tt> ((-r)↓⍴⍵),s</tt> .<tt> </tt> In other words, the argument<tt> ⍵ </tt>is treated as an array of <b>outer shape</b><tt> (-r)↓⍴⍵ </tt>of cells of shape<tt> (-r)↑⍴⍵</tt> ,<tt> </tt> and the (common) shape of the result of applying<tt> f </tt> to any cell is placed last in the shape of the overall result.</p> <p>Every function has an assigned rank. Thus<tt> < </tt>has rank<tt> 0 </tt> (i.e., applies to each scalar), and<tt> > </tt>has <b>infinite</b>, or <b>unbounded</b> rank, applying to its entire argument. For example:</p> <pre> a←1 2 3 ⊃ 4 5 6 a |1 2 3| |4 5 6| b←>a b 1 2 3 4 5 6 ⍴b 2 3 <b |1 2 3| |4 5 6| </pre> <p>The <b>rank</b> operator<tt> ⍤ </tt>produces a function of rank specified by its right argument. Thus:</p> <pre> <⍤1 b |1 2 3| |4 5 6| </pre> <p>Moreover, the ravel function has infinite rank and:</p> <pre> c←2 3 4⍴⍳24 ,c 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ,⍤2 c 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 c 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 </pre> <p>A negative argument of the rank operator specifies the <b>complementary</b> rank, that is the rank of the outer shape. For example:</p> <pre> ,⍤¯1 c 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 </pre> <p>In some instances, a primitive in conventional APL extends usefully by simply making an explicit assignment of the ranks implicit in its definition. For example,<tt> ⌹ </tt>is presently limited to rank<tt> 2 </tt>arguments, but extends usefully according to the general rules. More interestingly,<tt> ⍎ </tt>is defined on vectors, and if assigned rank<tt> 1</tt> ,<tt> </tt> can be used in the manner illustrated below:</p> <pre> ⍎ch←⍕2 2⍴⍳4 0 1 2 3 </pre> <a name="xc2"></a> <p><b>The Transpose Operator</b></p> <p>It is sometimes necessary to move certain axes of the argument before applying a function. Although the dyadic transpose function can perform this, it is much more convenient to use the transpose operator defined as follows:</p> <p><tt> f⍥k⍵ </tt>Applies<tt> f </tt> after moving axes<tt> k </tt>to the rear.</p> <p><tt> k⍥f⍵ </tt>Applies<tt> f </tt> after moving axes<tt> k </tt>to the front.</p> <p>For example:</p> <pre> ,⍥0 c 0 12 1 13 2 14 3 15 4 16 5 17 6 18 7 19 8 20 9 21 10 22 11 23 1 2⍥, c 0 12 1 13 2 11 3 15 4 16 5 17 6 18 7 19 8 20 9 21 10 22 11 23 ,⍤2⍥0 c 0 12 1 13 2 14 3 15 4 16 5 17 6 18 7 19 8 20 9 21 10 22 11 23 <⍤2⍥0 c | 0 12| | 4 16| | 8 20| | 1 13| | 5 17| | 9 21| | 2 14| | 6 18| |10 22| | 3 15| | 7 19| |11 23| </pre> <p>The last two examples above involve a sequence of operators, and it should be noted that an operator has “long left scope”, applying to the result of the entire operator sequence to its left. Thus,<tt> ,⍤2⍥0 </tt>is equivalent to<tt> (,⍤2)⍥0</tt> ,<tt> </tt> not to<tt> ,⍤(2⍥0)</tt> .<tt> </tt> This may be emphasized by assigning a name to the intermediate (function) result produced:</p> <pre> r2←,⍤2 r2 c 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 r2⍥0 0 12 1 13 2 14 3 15 4 16 5 17 6 18 7 19 8 20 9 21 10 22 11 23 </pre> <p>For transpositions on an argument of arbitrary rank, the transpose operator used in conjunction with the identity function<tt> ⊢ </tt> can often be much more convenient than the transpose function. For example, to move axes<tt> k </tt>to the rear:</p> <pre> ⊢⍥⍵k ←→ (⍋((~a∊k)/a←⍳⍴⍴⍵),k)⍉⍵ </pre> <a name="xc3"></a> <p><b>Dyadic Functions</b></p> <p>If the function<tt> g←f⍤r </tt>is to be applied dyadically as well as monadically (the only cases addressed in the preceding sections), then it is necessary that<tt> r </tt>specify three independent ranks, the monadic, the left, and the right. The general argument<tt> r </tt>is therefore a three-element vector that specifies the ranks in the order just indicated. Moreover,<tt> r </tt>is extended by reshape if necessary, so that<tt> f⍤r ←→ f⍤(⌽3⍴⌽r)</tt> .</p> <p>The following example shows the behaviour of a useful catenation function that has differing left and right ranks:</p> <pre> g←,⍤¯ 0 1 a←2 3⍴⍳6 7 8 g a 7 0 1 2 8 3 4 5 7 8 ∘.g a 7 0 1 2 7 3 4 5 8 0 1 2 8 3 4 5 h←∘.g ⍴b←3 4 5 h 7 8 h a 3 2 2 5 0 0{b 3 7 0 1 2 3 7 3 4 5 </pre> <p>If<tt> h←f⍤r </tt>is a function of higher rank than<tt> f</tt> ,<tt> </tt> then<tt> f </tt>and<tt> h </tt>may be indistinguishable when used in the expressions<tt> ⍺f⍵ </tt> and<tt> ⍺h⍵</tt> ,<tt> </tt> but may produce quite different results under the application of an operator. More precisely, if<tt> i </tt>and<tt> j </tt> are non-negative scalars and if the rank of<tt> f </tt>is<tt> i</tt> ,<tt> </tt> then<tt> h←f⍤(i+j) </tt>agrees with<tt> f </tt>in direct application, but may differ from it under application of an operator.</p> <p>For example, the rank of the scalar function<tt> × </tt>is<tt> 0</tt> ,<tt> </tt>and:</p> <pre> t1←×⍤1 a←2 3⍴⍳6 (a×a)-:a t a 1 ⍴a∘.×a 2 3 2 3 a ∘.t1 a 0 1 4 0 4 10 0 4 10 9 16 25 </pre> <p>The left brace denotes a dyadic indexing function called <b>from</b>. Its left and right ranks are<tt> 1 </tt> and<tt> ¯</tt> ,<tt> </tt>and:</p> <pre> 1 2 3{a3 ←→ a3[1;2;3] </pre> <p>For example:</p> <pre> a←2 3 4⍴⍳24 1 2 3{a 23 </pre> <p>If the left argument of<tt> { </tt> is of rank greater than<tt> 1</tt> ,<tt> </tt> then the normal rules of extension apply, giving the useful “scattered” indexing:</p> <pre> i←?4 3⍴2 i 1 1 0 0 0 0 1 1 1 1 1 0 i{a 16 0 17 16 </pre> <p>If<tt> j </tt>is a non-simple vector (i.e., including one or more elements produced by the enclose function<tt> <</tt> ),<tt> </tt> then the disclosed elements of<tt> i </tt>apply as follows:</p> <pre> i{a3 ←→ a3[>i[0];>i[1];>i[2]] </pre> <p>For example, using the link function<tt> ⊃ </tt> (that encloses its left argument and catenates it to the right, first enclosing the right if it is simple):</p> <pre> i←1⊃1 2⊃0 3 i{a 16 19 20 23 </pre> <p>This generalization may also be written as:</p> <pre> ⍺{⍵ ←→ ({⍺){⍵ </pre> <p>using the monadic case of<tt> {</tt> ,<tt> </tt> the cartesian product discussed in the following section. For example:</p> <pre> {i 1 1 0 1 1 3 1 2 0 1 2 3 ({i){a 16 19 20 23 </pre> <a name="xc4"></a> <p><b>The Cartesian Product</b></p> <p>The asymmetric catenation function<tt> g←,⍤¯ 0 1 </tt>illustrated earlier can be used to add a unit final axis. Thus:</p> <pre> 8 9 ∘.g '' 8 9 ⍴8 9 ∘.g '' 2 1 </pre> <p>It can also be used to form a cartesian product of arrays:</p> <pre> c←2+b←2+a←1 2 r←a ∘.g b ∘.g c ∘.g '' r 1 3 5 1 3 6 1 4 5 1 4 6 2 3 5 2 3 6 2 4 5 2 4 6 </pre> <p>Finally, if<tt> i </tt>is the vector<tt> i←a⊃b⊃c</tt> ,<tt> </tt> then the reduction of<tt> i,∘ </tt>by<tt> ∘.g¨> </tt>produces the enclosed cartesian product of the elements of<tt> i</tt> .<tt> </tt>Thus:</p> <pre> i←a⊃b⊃c r≡> ∘.g¨>/i,∘ 1 </pre> <p>The operator<tt> ¨ </tt>(<b>dual</b>) used in the foregoing expression is defined by:</p> <pre> f¨g⍵ ←→ g⊂ f g ⍵ ⍺f¨g⍵ ←→ g⊂ (g⍺)f g ⍵ </pre> <p>where<tt> ⊂ </tt>(<b>con</b>) denotes the inverse operator. The effect of<tt> f¨>⍵ </tt>is to apply<tt> f </tt> to (the disclose of) each of the<tt> ×/⍴⍵ </tt> enclosed elements of<tt> ⍵</tt> ,<tt> </tt> and to enclose each result.</p> <p>The cartesian product function will be defined as the monadic case of<tt> {</tt> .<tt> </tt>Formally:</p> <pre> {⍵ ←→ > ∘.(,⍤¯ 0 1)¨>/(<⍤>⍵),∘ </pre> <p>Its use in the definition of the dyadic case was shown in the preceding section, namely:</p> <pre> ⍺{⍵ ←→ ({⍺){⍵ </pre> <p>Since<tt> { </tt>applied to a simple vector yields the vector unchanged, the definition applies (trivially) to a simple vector left argument as well as to a vector of enclosed elements. Note that it is the case of a simple argument that required the expression<tt> (<⍤>⍵) </tt> instead of<tt> ⍵ </tt>in the definition of<tt> {⍵ </tt>above.</p> <p>The definition of<tt> ⍺{⍵ </tt>is extended further to allow <b>abbreviated</b>, <b>negative</b>, and <b>complementary</b> indexing. For example:</p> <pre> a←2 3 4⍴⍳24 1 2{a 20 21 22 23 1 ¯1{a 20 21 22 23 i←1⊃(<2)⊃0 3 i |1| ||2|| |0 3| i{a 12 15 16 19 </pre> <p>Because an element of the form<tt> <<'' </tt> will select all along the corresponding axis, an expression such as<tt> ((3⍴<<''),<k){a4 </tt> can be used to select an index<tt> k </tt> along the last axis. However, if it is also desirable to bring the last axis to the front, it is more convenient to use the “display” function<tt> d</tt> ,<tt> </tt> defined and illustrated below:</p> <pre> d←¯1⍥{ 1 d 3 3 3⍴⍳27 1 4 7 10 13 16 19 22 25 0 d 3 3 1⍴⍳9 0 1 2 3 4 5 6 7 8 </pre> <p>The last example above shows the production of an easily readable display of an array with a final unit axis. This will be used later in the discussion of permutations.</p> <a name="xc5"></a> <p><b>Operators on Non-Scalar Functions</b></p> <p>Some examples of the application of operators (such as the outer product and the rank) have already appeared in earlier sections. We will here provide further examples involving the reduction operators<tt> / </tt>and<tt> ⌿</tt> ,<tt> </tt> as well as the scans<tt> \ </tt> and<tt> ⍀</tt> ,<tt> </tt> which introduce supernumerary axes.</p> <p>The expression<tt> f⌿⍵ </tt>splits<tt> ⍵ </tt> along its leading axis, and applies<tt> f </tt> between the resulting subarrays. Thus, if<tt> a←?3 4 5⍴9 </tt>then</p> <pre> f⌿a ←→ (0{a) f (1{a) f 2{A </pre> <p>For example:</p> <pre> a←3 3⍴⍳9 ∘.×⌿a 0 0 0 0 0 0 0 0 0 18 21 24 24 28 32 30 35 40 36 42 48 48 56 64 60 70 80 p←3 3 1⍴1 0 2 2 0 1 2 1 0 d←¯1⍥{ 0 d p 1 0 2 2 0 1 2 1 0 ,{⌿p 2 0 1 </pre> <p>The last result above is the “product of the permutations” represented by the rows of<tt> p</tt> .</p> <p>The other reduction<tt> </tt>(<tt>f/</tt>)<tt> </tt> splits along the last axis. For example:</p> <pre> a←i∘.×10*i←⍳3 a 0 0 0 1 10 100 2 20 200 ⍴r←∘.(,⍤0)/a 3 3 3 2 2 1 2 { r 1 20 1 0 1 20 1 100 1 20 1 200 </pre> <p>A scan of the form<tt> f⍀⍵ </tt>applies<tt> f⌿⍵ </tt> to each of a set of subarrays<tt> (,⍤0⍳k){⍵</tt> ,<tt> </tt> for each<tt> k∊1+⍳1↑⍴⍵</tt> ,<tt> </tt> and the supernumerary axis (of length<tt> 1↑p⍵</tt> )<tt> </tt> is placed <b>before</b> the axes contributed by the individual results. This will be illustrated in the scan<tt> {⍀p</tt> ,<tt> </tt> where<tt> p </tt>is the permutation matrix used above to illustrate the reduction<tt> {⌿</tt> :</p> <pre> 0 (d←¯1⍥{) p 1 0 2 2 0 1 2 1 0 </pre> <p>The subarrays involved in the scan<tt> {⍀ </tt> may be produced and displayed as follows:</p> <pre> g←,⍤0⍤⍳ 0 d (g 1){p 1 0 2 0 d (g 2){p 1 0 2 2 0 1 0 d (g 3){p 1 0 2 2 0 1 2 1 0 </pre> <p>The scan<tt> {⍀p </tt>therefore gives all of the permutations produced by reductions over these subarrays:</p> <pre> 0 d {⍀p 1 0 2 0 2 1 2 0 1 </pre> <p>The alternate scan<tt> f\ </tt>is defined analogously, with the split occurring along the <b>last</b> axis, and with the supernumerary axis placed <b>last</b>. For example:</p> <pre> ×\3 3⍴⍳9 0 0 0 3 12 60 6 42 336 </pre> <a name="xc6"></a> <p><b>Til, Cut, and Bind</b></p> <p>The operators discussed in this section are not essential to the rationalization program, but they can be used to further exploit, and therefore to demonstrate, the power of the essential facilities. In what follows, we will use the fact that the <b>con</b> operator<tt> ⊂ </tt>is (in the dyadic use of the resulting derived function) a commutation, that is:</p> <pre> ⍺ f⊂ ⍵ ←→ ⍵ f ⍺ </pre> <p>The til operator, defined by <pre> ⍺ f}g ⍵ ←→ (g ⍵) f ⍺ f}g ⍵ ←→ (g ⍵) f ⍵ </pre> <p>can be used in a variety of ways. For example:</p> <pre> f←÷⍤1 g←⌽ a←2 4 5 b←10 2 4 a f}g b Reverse b and divide by a 2 0.5 2 a f}g⊂ b Reverse a and divide by b 0.5 2 0.5 (a “left composition” in which g applies only to the left argument) a f⊂}g b Right composition 0.5 2 0.5 </pre> <p>If<tt> f </tt>is commutative, then right composition can be obtained more simply by the expression<tt> f}g</tt> .<tt> </tt> For example:</p> <pre> a +}÷ b 2.1 4.5 5.25 +}÷/c←2 4 5 6 2.23846 +}÷\c 2 2.25 2.2381 2.23846 </pre> <p>The case<tt> +}÷/c </tt>is equivalent to<tt> 2+÷4+÷5+÷6</tt> ,<tt> </tt> and is called the continued fraction represented by<tt> c</tt> ;<tt> </tt> the case<tt> +}÷\c </tt>yields the “convergents” to the continued fraction.</p> <p>The most important property of the til operator remains to be stated, namely:</p> <pre> f}g}h ⍵ ←→ (g⍵) f (h⍵) </pre> <p>In other words,<tt> f}g}h ⍵ </tt>applies a dyadic function<tt> f </tt>to the results of the monadic functions<tt> g </tt>and<tt> h</tt> .<tt> </tt> For example:</p> <pre> f←'⍵*2'∇∘⍤0 g←'⍵*3'∇∘⍤0 +}f}g 1 2 3 Often denoted by f+g without 2 12 36 indicating that + is an operator rather than a function -}f}g 1 2 3 0 ¯4 ¯18 i←'⍵=⌊⍵'∇∘⍤0 p←'⍵>0'∇∘⍤0 n←¯1 ¯.5 0 .5 1 ∧}i}p n 0 0 0 0 1 ∨}i}p n 1 0 1 1 1 ≠}i}p n 1 0 1 1 0 </pre> <p>The <b>cut</b> operator takes an integer left argument and a function right argument and applies it to pieces cut from the right argument of the derived function, putting the supernumerary axes contributed by the set of pieces in first place. The type of cut is determined by the left argument of the operator, and the points of cutting by the left argument of the derived function. The cuts are along the leading axis. For example:</p> <pre> t←'abcdefghij' b←0 0 1 0 0 0 1 1 0 0 b ¯1⍤< t A ¯1-cut begins pieces at 1's |def| || |ij| and excludes cut points b 1⍤< t A 1-cut begins at 1's |cdef| |g| |hij| and includes cut points b ¯2⍤< t (2 ¯2)-cuts end at 1's |ab| |def| || b 2⍤< t |abc| |defg| |h| b ¯1⍤(+/) ⍳10 12 0 17 b 1⍤(+/) ⍳10 14 6 24 m←⍉2 10⍴'abcdefghijk' m ak ba cb dc ed fe gf hg ih ji (4↑1) ¯1⍤< m |ak| |ed| |ih| |ba| |fe| |ji| |cb| |gf| |dc| |hg| s←'now it is' ¯1⍤< ' ',s Monadic (1 ¯1)-cuts use the |now| |it| |is| leading element as a delimiter 1⍤< ' ',s | now| | it| | is| ¯2⍤< s,' ' Monadic (2 ¯2)-cuts use the last |now| |it| |is| element as delimiter 2⍤< s,' ' |now | |it | |is | </pre> <p>The <b>general</b> cut<tt> 0⍤f </tt>has left rank<tt> 2 </tt>and infinite right rank, so that a left argument of rank greater than<tt> 2 </tt>produces a set of cuts. The first row of the left argument specifies the beginning point, and the magnitudes of the last row specify the size of the window, with a negative value producing a reversal along the corresponding axis. For example (using the identity function<tt> ⊢</tt> ):</p> <pre> a←>1 1⊃2 2 a 1 1 2 2 a 0⍤⊢ m←4 4$i.16 5 6 9 10 (>1 1⊃¯2 2) 0⍤< m | 9 10| | 5 6| </pre> <p>The<tt> ¯3</tt>-cut<tt> ⍺ ¯3⍤f ⍵ </tt> provides a tessellation, with the movement specified by<tt> ⍺[0;]</tt> ,<tt> </tt> and the window again by<tt> ⍺[1;]</tt> .<tt> </tt> For example (with<tt> ⎕ps </tt> set to<tt> -1 1 3 3</tt> ):</p> <pre> a←2 2⍴2 a ¯3⍤< m ___ ___ | | | | |0 1| |2 3| |4 5| |6 7| |___| |___| _____ _____ | | | | | 8 9| |10 11| |12 13| |14 15| |_____| |_____| a←>1 1⊃2 2 ⍴r←a ¯3⍤⊢ m 3 3 2 2 1{r 4 5 8 9 5 6 9 10 6 7 10 11 </pre> <p>In the expression<tt> ⍺ f.k ⍵</tt> ,<tt> </tt> the operator causes<tt> f </tt>to be applied to the arguments with their first<tt> k </tt> axes “bound” (and necessarily agreeing), and with the remaining free axes (exclusive of those demanded by cells as determined by the ranks of<tt> f</tt> )<tt> </tt> forming an outer product. The main point is best illustrated by a scalar function<tt> f </tt> in which no axes are demanded by cells:</p> <pre> a←10×b←2 3⍴⍳6 a +. 2 b 0 11 22 33 44 55 a +. 1 b 0 1 2 10 11 12 20 21 22 33 34 35 43 44 45 53 54 55 ⍴r←a +. 0 b 2 3 2 3 r≡a∘.+b 1 </pre> <p>The monadic case of<tt> f.k </tt>provides<tt> k </tt> successive reductions by<tt> f </tt>over the leading axes. For example:</p> <pre> a←2 3 4 5⍴⍳120 +. 2 a 300 306 312 318 324 330 336 342 348 354 360 366 372 378 384 390 396 402 408 414 </pre> <p>For many functions (particularly for non-scalar functions) it is important to note that the reductions are carried out in the manner illustrated by<tt> f. 3 ⍵ ←→ f⌿ f⌿⍤¯1 f⌿⍤¯2 ⍵ </tt></p> <br><a name="xd"></a> <p><b>Appendix D. APL2 versus a Comparable Subset</b></p> <p>This section presents comparisons between the facilities of APL2 <acronym title="APL2 Language Manual (IBM Corporation, SB21 3015, June 1982)">[3]</acronym> and a roughly equivalent subset of the facilities defined in this paper. The restricted subset (to be referred to as RS) embraces:</p> <table> <tr><td valign=top>1.</td><td> </td><td> The functions<tt> <</tt> ,<tt> ></tt> ,<tt> </tt>and<tt> ≡ </tt> (enclose, disclose, and match), and the operators<tt> ⍤</tt> ,<tt> ⍥</tt> ,<tt> </tt>and<tt> ¨ </tt> as defined (for function arguments only) in <acronym title="Robert Bernecky and Kenneth E. Iverson, Operators and Enclosed Arrays (I.P. Sharp, Proceedings of the User Meeting, 1980)">[4]</acronym>. <br> </td></tr> <tr><td valign=top>2.</td><td> </td><td> Argument ranks assigned to all primitive functions, and a rank operator (used in the form<tt> f⍤r</tt> )<tt> </tt> that assigns rank<tt> r </tt>to a derived function. <br> </td></tr> <tr><td valign=top>3.</td><td> </td><td> A single rule, common to all functions, for extending them to arguments of higher rank; the result shape is the catenation of the <b>outer shape</b> (exclusive of the <b>cell</b> shapes demanded by the ranks of the function ranks) with the common result shape produced by applying the function to individual cells. <br> </td></tr> <tr><td valign=top>4.</td><td> </td><td> The functions link<tt> </tt>(<tt>⊃</tt>)<tt> </tt> and from<tt> </tt>(<tt>{</tt>),<tt> </tt> including the dyadic case of<tt> i¨{ </tt> (which provides a merge equivalent to indexed assignment. <br> </td></tr> <tr><td valign=top>5.</td><td> </td><td> The transpose operator, which applies a function<tt> f </tt> after effecting a transpose;<tt> f⍥i </tt>moves axes<tt> i </tt> to the rear, and<tt> i⍥f </tt>to the front. <br> </td></tr> <tr><td valign=top>6.</td><td> </td><td> Use of the form<tt> a←exp </tt>to assign a name to a function or operator as well as to a variable, and of the function definition operator<tt> ∇ </tt> which applies to vectors representing (in direct definition form) the monadic and dyadic cases of a function. </td></tr> </table> <p>The functions from<tt> </tt>(<tt>{</tt>)<tt> </tt>and merge<tt> </tt>(<tt>i¨{</tt> ),<tt> </tt> and the rank and transpose operators obviate all uses of brackets and semicolons. The <b>discussion</b> of RS will therefore be based on the assumption that their use is excluded, even though, for reasons of compatibility, they will continue to function as in conventional APL.</p> <p>The comparisons made in this section are more theoretical than practical, concentrating on general questions such as implications for syntax, function classifications, and domains of operators. More practical comparisons of convenience, ease of learning, etc. are better made by the reader, either by drawing from his own applications, or from definitions and examples given in the APL2 manual <acronym title="APL2 Language Manual (IBM Corporation, SB21 3015, June 1982)">[3]</acronym> and the companion Introduction manual <acronym title="APL2 Introduction Manual (IBM Corporation, SB21 3039, June 1982)">[10]</acronym> as well as from this paper.</p> <p>For example, one might take examples of strands and of heterogeneous arrays from the APL2 publications and write them completely in RS, and take function definitions such as<tt> r←,⍤2 </tt> and write them completely in APL2.</p> <a name="xd1"></a> <p><b>Syntax.</b> A useful measure of the complexity of a set of syntax rules is the required <b>scope</b>, that is, the maximum number of elements in the execution stack which must either be involved in the determination of the next action to be taken, or be used in that action. This measure is meaningful only on the assumption that each element is a normal operator, function, or variable, that is, an element does not incorporate further information relevant to another element or elements.</p> <p>We will further assume that parentheses are handled by recursion on any segment enclosed by matching parentheses, and that parentheses are therefore not considered in assessing scope. However, this exclusion can not apply to an “unusual” use of parentheses, such as the usage<tt> (c\[a]v)←x </tt>in APL2, in which the result of the parenthesized expression is a “qualified” name.</p> <p>Under the foregoing assumptions, the scope in RS is<tt> 4</tt> .<tt> </tt>In APL2:</p> <table> <tr><td valign=top>1.</td><td> </td><td> Strands impose infinite scope. <br> </td></tr> <tr><td valign=top>2.</td><td> </td><td> The scope requirements of bracketed axis operators remain, or are further exaggerated by the introduction of semicolons within them. <br> </td></tr> <tr><td valign=top>3.</td><td> </td><td> Although the index function (denoted by the composite symbol “squad”) shows some similarity to<tt> { </tt>in RS, it is not clear that an expression such as<tt> (1 2⊃?3 4⍴2){a3 </tt>could be conveniently expressed without the use of bracket indexing, and it may be reasonable to assume that bracket indexing is not superseded by squad. <br> </td></tr> <tr><td valign=top>4.</td><td> </td><td> Although the use of bracket indexing in indexed assignment may be partly (or even wholly) superseded by constructs such as<tt> (1 1⍉v)←c</tt> ,<tt> </tt> this special use of parentheses to enclose a “qualified name” would appear to have the same implications for syntax as the use of bracket-index assignment. <br> </td></tr> <tr><td valign=top>5.</td><td> </td><td> The introduction of <b>ambiguous symbols</b> (that is<tt> /</tt> ,<tt> ⌿</tt> ,<tt> \</tt> ,<tt> </tt> and<tt> ⍀</tt> )<tt> </tt> to denote both a monadic operator and a dyadic function, would appear to complicate the syntax. Thus, although the expressions<tt> +/1 2 </tt>and<tt> //1 2 </tt> are analyzed similarly, the expressions<tt> ⍴+/1 2 </tt>and<tt> ⍴//1 2 </tt>are not. </td></tr> </table> <a name="xd2"></a> <p><b>Function Classes.</b> In conventional APL, functions are, explicitly or implicitly, divided into a number of overlapping classes, and the behaviour of a function depends, in significant ways, on the classes to which it belongs. Thus:</p> <table> <tr><td valign=top>1.</td><td> </td><td> Scalar functions are all of rank<tt> 0</tt> ,<tt> </tt> but, more significantly, they alone are in the domain of the operators<tt> /</tt> ,<tt> ⌿</tt> ,<tt> \</tt> ,<tt> ⍀</tt> ,<tt> </tt> and<tt> . </tt>(dot). <br> </td></tr> <tr><td valign=top>2.</td><td> </td><td> “Bracket” functions, which include certain derived functions such as<tt> +/ </tt>and<tt> +⍀ </tt> as well as the functions<tt> ⌽ </tt>and<tt> ⊖ </tt> are in the domain of the “bracket axis specification”. <br> </td></tr> <tr><td valign=top>3.</td><td> </td><td> Some functions (such as<tt> ~</tt> ,<tt> ↓</tt> ,<tt> ↑</tt> ,<tt> ⊥</tt> ,<tt> ⊤</tt> ,<tt> </tt> and<tt> ⍎</tt> )<tt> </tt> are fixed in valence, and produce syntax errors when used inappropriately. <br> </td></tr> <tr><td valign=top>4.</td><td> </td><td> Defined functions are included in class 3 above, but excluded from classes<tt> 1 </tt>and<tt> 2</tt>. <br> </td></tr> <tr><td valign=top>5.</td><td> </td><td> Derived functions are excluded from class<tt> 1</tt>,<tt> </tt> and some, but not all, are excluded from class<tt> 2</tt>. </td></tr> </table> <p>In RS all such class distinctions are removed. However, each function is assigned a set of ranks, the ranks for all primitives of conventional APL being<tt> 0</tt>,<tt> 1</tt>,<tt> 2</tt>,<tt> </tt>or unbounded.</p> <p>In APL2, some of these distinctions are removed in that operators such as reduction and inner product apply to non-scalar and defined and derived functions.</p> <p>However, class<tt> 2 </tt>is not only retained, but extended (to scalar functions, to<tt> ↑</tt> ,<tt> </tt>etc.), and class<tt> 3 </tt>(fixed valence) is also retained and extended, as evidenced by entries under “monadic” and “dyadic” in the glossary, by references to dyadic functions in the definitions of certain operators, and by the fact that the new bracket axis operator (distinct from the conventional “bracket axis specification” referred to in the definition of class<tt> 2</tt>)<tt> </tt> produces a function which is specifically monadic or dyadic.</p> <p>Two further classes are introduced in APL2, called <b>pervasive</b> and <b>selection</b>: members of the former applying down through any structure of enclosures, and members of the latter being permitted to the left of assignment. No provision appears to be made for making a defined or derived function a member of either of these classes.</p> <a name="xd3"></a> <p><b>Depth Functions.</b> APL2 provides two significant facilities which apply at “depth” in the enclosure structure of an argument, the dyadic <b>pick</b> function, and the pervasive functions. RS provides no primitive corresponding to <b>pick</b>; it could be defined recursively by:</p> <pre> pick←''∇('→2+0=⍴⍺'⊃'(>0{⍺){(1↓⍺)∆⍵'⊃'⍵') </pre> <p>If frequent use demands greater convenience and efficiency, the pick function could be incorporated as a primitive. If so, the dyadic case of<tt> i¨pick </tt> should provide the merge corresponding to the “selective specification” of the form<tt> (l⊃r)←x </tt>provided in APL2.</p> <p>Since pervasiveness is a property assigned to functions, it would, in the framework of RS, be provided by an operator. Such an operator could be applied to any function (defined or derived as well as primitive) and, if defined to be dyadic, could provide greater variety. Thus a variable<tt> p </tt>in<tt> f op p </tt> could provide application at any depth from the top, or any distance from the leaves; a <b>function</b><tt> p </tt> (that is, a proposition) could specify the condition at the level where<tt> f </tt>is to apply.</p> <a name="xd4"></a> <p><b>Array Formation.</b> If each essential space in an expression is counted as a character, then the link function and strand notation used to form non-simple vectors from simple vectors require expressions of nearly identical length. For example:</p> <table> <tr><td>Strand</td><td> </td><td>Link</td></tr> <tr><td><tt>(1 2)(3 4)(5 6)7 8</tt></td> <td> </td><td><tt>1 2⊃3 4⊃5 6⊃7 8</tt></td></tr> <tr><td><tt>((1 2)3 4)((5 6)7 8)</tt></td><td> </td><td><tt>(1 2⊃3 4)⊃<5 6⊃7 8</tt></td></tr> <tr><td><tt>a b c d e f g h</tt></td> <td> </td><td><tt>a⊃b⊃c⊃d⊃e⊃f⊃g⊃h</tt></td></tr> <tr><td><tt>(a b)(c d)(e f)(g h)</tt></td><td> </td><td><tt>(a⊃b)⊃(c⊃d)⊃(e⊃f)⊃<(g⊃h)</tt></td></tr> <tr><td><tt>a(b(c(d(e f))))</tt></td> <td> </td><td><tt>a⊃<b⊃<c⊃<d⊃<e⊃f</tt></td></tr> </table> <p>In conventional APL, the precedence o£ operators obviated parentheses around operator expressions, as in<tt> a+.×b</tt> ,<tt> </tt> and in RS the precedence and scope rules for operators extend this convenience to expressions such as<tt> f⍤a b</tt> ,<tt> </tt> regardless of whether<tt> a </tt> is a function or a variable. APL2 adopts the same rule for operators, but because strands take precedence over everything, an operator expression with a variable right argument must be parenthesized.</p> <p>In conventional APL, two vector constants are never juxtaposed. In both RS and APL2, however, juxtaposition may occur in the case of any operator having a variable right argument (necessarily a user-defined operator in the case of APL2). In that event, the divide between the constants must be indicated by some delimiter. Thus:</p> <pre> f⍤1 2 (3 4 5) f⍤(1 2) 3 4 5 f⍤1 2 a← 3 4 5 (f⍤1 2) 3 4 5 f⍤1 2⊢3 4 5 </pre> <p>In RS, any one of these may be used, the first two being preferred because they clearly indicate the purpose of the parentheses, and the third being used if there are extraneous reasons for naming the right argument. In APL2, strands limit the choice to the fourth.</p> <p>Retention of a valence classification for functions may have some implication for strands. Thus, if<tt> f </tt>is strictly monadic, the expression<tt> a~b </tt>might be considered identical to<tt> a(~b)</tt> ,<tt> </tt> since the strictly monadic function would presumably be executed first.</p> <p>Although the valence classification is made in conventional APL (with<tt> a~b </tt>yielding a syntax error rather than a domain error) the valence classification has no serious consequences, because the juxtaposition of the two variables occasions an immediate error. Paradoxically, the function<tt> ~ </tt>is actually treated as ambivalent in the sense that the name<tt> a </tt> in the expression<tt> a~b </tt> is evaluated <b>before</b> the syntax error is reported, as may be seen by making<tt> a </tt>a shared variable (perhaps<tt> ⎕</tt> )<tt> </tt> or a niladic function that specifies a global variable.</p> <a name="xd5"></a> <p><b>Domains of Operators.</b> In conventional APL, the domains of operators are defined by one general rule (which excludes all defined functions), and by specific lists, the list of “scalar primitives” for all but the bracket axis operator, and a second list (which includes some derived functions) for it.</p> <p>Moreover, the domains of the derived functions produced are limited in ways which depend upon the arguments of the operators, depending upon the normal definition of the argument (as in<tt> ÷/4 0</tt> ),<tt> </tt> or upon an “attribute” that it may possess (as in<tt> ⍲/⍳0</tt> ).</p> <p>In RS, the domains of operators are unrestricted, although the domains of the resulting derived functions continue to be restricted in ways analogous to those in conventional APL. Thus the domain of<tt> f¨g </tt> will be restricted by the domains of<tt> g</tt> ,<tt> f</tt> ,<tt> </tt>and<tt> g⊂ </tt> (that is<tt> g </tt>inverse). In particular, the domain of<tt> f¨g </tt>is empty if the domain of<tt> g⊂ </tt>is empty.</p> <p>In APL2, the domains of most operators are unrestricted. However, the list of functions subject to (bracket) axis specification is not only maintained (as required for compatibility, even in RS), but is extended, as in<tt> a+[2]b</tt> ,<tt> </tt>and in<tt> a↑[2]b</tt> .<tt> </tt> In the latter case of<tt> ↑</tt> ,<tt> </tt> the “default” axis used when the axis specification is absent is not the final axis used for similar cases, but <b>all</b> axes.</p> <p>Although the bracket notation used to represent it in conventional APL tends to obscure the matter, the axis operator is, in effect, dyadic, applying to a function “left argument” and a variable “right argument”. In APL2, the bracket axis operator is defined to be monadic, seeming to imply that there is an indeterminate number of such operators, such as<tt> [1;1]</tt> ,<tt> </tt> and<tt> [1;2]</tt> ,<tt> </tt>etc.</p> <a name="xd6"></a> <p><b>Prototypes.</b> Prototypes in APL2 are an extension of the notion (implicit in the difference in the results of<tt> 1↑⍳O </tt>and<tt> 1↑''</tt> )<tt> </tt> that an array<tt> a </tt>incorporates some information other than its shape and the values of each of its elements.</p> <p>In RS, compatibility with conventional APL is maintained, but no new distinctions are introduced. Specifically,<tt> 1↑0⍴1j1 </tt>and<tt> 1↑0⍴(1 2 3⊃'ab') </tt> both yield<tt> 0</tt> .</p> <p>This is a fundamental difference that cannot be eliminated (as can the lack of a pervasive class of functions) by the introduction of an appropriate operator.</p> <a name="xd7"></a> <p><b>Heterogeneous Arrays.</b> RS does not include the heterogeneous arrays of APL2, and the production of equivalent constructs requires greater use of enclosure. However, the structure of RS does not preclude their introduction.</p> <a name="xd8"></a> <p><b>Permissive Enclose.</b> The monadic enclose functions defined in RS<tt> </tt>(<tt><</tt>)<tt> </tt> and in APL2<tt> </tt>(<tt>⊂</tt>)<tt> </tt>differ in one respect: if<tt> s </tt>is a simple scalar, then<tt> s≡⊂s</tt> ,<tt> </tt>but<tt> ~s≡<s</tt> .<tt> </tt> Although<tt> < </tt>can therefore produce some structures not producible by<tt> ⊂</tt> ,<tt> </tt> the differences between them (in the contexts of the respective systems) cannot, in most cases, be discerned.</p> <p>The function<tt> { </tt>in RS provides an example where the difference is significant: because a doubly enclosed element of the left argument provides <b>complementary</b> indexing, the value of<tt> <<k </tt>must be distinguishable from<tt> <k</tt> ,<tt> </tt> even in the case of a scalar<tt> k</tt> .</p> <p>A similar situation would arise in the definition of an indexing function<tt> f </tt> in which<tt> a f i </tt>selects elements from<tt> a </tt> and incorporates them in the same “enclosure structure” as<tt> I</tt> .<tt> </tt> However, the difference would be discernible only in the case of some scalar element of<tt> i </tt> <b>and</b> a non-simple argument<tt> a</tt> .</p> <a name="xd9"></a> <p><b>General Remarks.</b> The following general contrasts may be noted:</p> <table> <tr><td valign=top>1.</td><td> </td><td> The definitions of function rank and of the disposition of result axes in RS permit the handling of constructs that would be handled by explicit encloses in APL2, and APL2 provides more facilities (such as pervasiveness) for operating “at depth”. <br> </td></tr> <tr><td valign=top>2.</td><td> </td><td> RS provides facilities which obviate the use of brackets and semicolons in both indexing and in operators; although alternative indexing functions in APL2 could supersede bracket indexing, the use of brackets as operators is not only retained, but extended. <br> </td></tr> <tr><td valign=top>3.</td><td> </td><td> <p>By assigning specified ranks to all functions, and by declaring all functions to be ambivalent, RS subsumes all in a single class, eliminating distinctions in the treatments of the classes (such as defined, derived, mixed) which occur in conventional APL.</p> <p>Although APL2 removes the confining distinction between primitives and defined and derived functions in the application of operators, it retains other function class distinctions of conventional APL, and introduces two further classes, pervasiveness, and “selectivity”.<br> </p> </td></tr> <tr><td valign=top>4.</td><td> </td><td> APL2 retains and extends the use of indexed assignment, whereas RS provides equivalent merge functions based upon the indexing function. <br> </td></tr> <tr><td valign=top>5.</td><td> </td><td> RS restricts the scope of syntax rules to<tt> 4</tt> ,<tt> </tt> whereas APL2 makes no corresponding restriction. </td></tr> </table> <br><a name="ref"></a> <p><b>References</b></p> <table> <tr><td valign=top>1.</td><td> </td><td><b>APL Language</b> (IBM Corporation, GC26-3847).</td></tr> <tr><td valign=top>2.</td><td> </td><td><b>APL*PLUS Nested Array System</b> (STSC, Inc., 1981).</td></tr> <tr><td valign=top>3.</td><td> </td><td><b>APL2 Language Manual</b> (IBM Corporation, SB21 3015, June 1982).</td></tr> <tr><td valign=top>4.</td><td> </td><td>Robert Bernecky and Kenneth E. Iverson, <a target=_parent href="http://www.jsoftware.com/papers/opea.htm"><b>Operators and Enclosed Arrays</b></a> (I.P. Sharp, Proceedings of the User Meeting, 1980).</td></tr> <tr><td valign=top>5.</td><td> </td><td>K.E. Iverson, <a target=_parent href="http://www.jsoftware.com/papers/APLSyntaxSemantics.htm"><b>APL Syntax and Semantics</b></a> (ACM, APL83).</td></tr> <tr><td valign=top>6.</td><td> </td><td> <a target=_parent href="http://www.jsoftware.com/papers/opfns.htm"><b>Operators and Functions</b></a> (IBM Corporation, RC7091, 1978).</td></tr> <tr><td valign=top>7.</td><td> </td><td>K.E. Iverson, <a target=_parent href="http://www.jsoftware.com/papers/satn42.htm"><b>Determinant-Like Functions Produced by the Dot Operator</b></a> (I.P. Sharp Technical Notes - SATN-42, April 1982).</td></tr> <tr><td valign=top>8.</td><td> </td><td>Kenneth E. Iverson and Peter K. Wooster, <b>A Function Definition Operator</b> (APL Quote Quad, Volume 12, Number 1, Proceedings of APL81, ACM September 1981).</td></tr> <tr><td valign=top>9.</td><td> </td><td>Arthur Whitney and Kenneth E. Iverson, <a target=_parent href="http://www.jsoftware.com/papers/APLModel.htm"><b>Practical Uses of a Model of APL</b></a> (Apl Quote Quad, Volume 13, Number 1, Proceedings of APL82, ACM, New York 1982).</td></tr> <tr><td valign=top>10.</td><td> </td><td><b>APL2 Introduction Manual</b> (IBM Corporation, SB21 3039, June 1982).</td></tr> </table> <br><a name="ack"></a> <p><b>Acknowledgements</b></p> <p>I am indebted to a number of my colleagues at I.P. Sharp Associates for many helpful discussions and suggestions, particularly to R. Bernecky, E.B. Iverson, E.E. McDonnell, R. Pesch, J.H. Schueler, D.L. Forkes, and L.H. Goldsmith.</p> <br><hr> <a name="err"></a> <p align=center><font size=+2>Errata</font></p> <table> <tr><td valign=top>•</td><td> </td><td> In Section A, just before the last displayed example, it should be “with the rest of<tt> a</tt> .<tt> </tt>Thus:” instead of “with the rest of<tt> a</tt> ,<tt> </tt>Thus:”. </td></tr> <tr><td valign=top>•</td><td> </td><td> In Section E, there should not be a blank line just before the last line of item d. </td></tr> <tr><td valign=top>•</td><td> </td><td> In Section F, in the paragraph that introduced the rank operator, it should say “both the right rank and the monadic rank are<tt> 3</tt> ” instead of “both right ranks are<tt> 3</tt> ”. </td></tr> <tr><td valign=top>•</td><td> </td><td> In Section F, in the displayed examples of the Conformance subsection: The result of<tt> ⍴a×. 1 (1 1 4⍴9) </tt> should be<tt> 2 3 4 1 4 </tt> instead of<tt> 2 3 4</tt> ;<tt> </tt> the next expression<tt> ⍴a×. 2 (3 4⍴9) </tt> should signal<tt> length error </tt> instead of giving a result of<tt> 2 3 4</tt> ;<tt> </tt> finally, the last expression should not have a trailing right parenthesis. </td></tr> <tr><td valign=top>•</td><td> </td><td> In Section G, in the paragraph following the definition of outer product and inner product, it should say “leading position.)” instead of “leading position).”. </td></tr> <tr><td valign=top>•</td><td> </td><td> In Section H, item 1 of the conclusion should say<tt> i ↑¨⍵ f </tt>instead of<tt> i {¨⍵ f</tt> . </td></tr> <tr><td valign=top>•</td><td> </td><td> In Section K, in the paragraph introducing<tt> ⍥</tt> ,<tt> </tt> the first instance of the word “upon” should be in bold. </td></tr> <tr><td valign=top>•</td><td> </td><td> In Section K, in the Cut Operator subsection, the expression for the monadic case of<tt> 0⍤f ⍵ </tt> is missing a leading left parenthesis. </td></tr> <tr><td valign=top>•</td><td> </td><td> In Appendix C, in the Til, Cut, and Bind subsection, the example should be<tt> (4↑1) 1⍤< m </tt>instead of<tt> (4↑1) ¯1⍤< m</tt> . </td></tr> <tr><td valign=top>•</td><td> </td><td> In Appendix D, item 4 of the description of RS is missing a closing right parenthesis. </td></tr> <tr><td valign=top>•</td><td> </td><td> In Appendix D, in the third paragraph of the Domains of Operators subsection, the comma is missing from “(that is,<tt> g </tt>inverse)”. </td></tr> <tr><td valign=top>•</td><td> </td><td> Reference 6 should have K.E. Iverson as the author. </td></tr> <tr><td valign=top>•</td><td> </td><td> Reference 9 should say “APL Quote Quad” instead of “Apl Quote Quad”. </td></tr> </table> <br><hr> <font size=-1> <p>Originally appeared as I.P. Sharp Research Report #1, Revision 1, 1983-04-04.</p> <p><script src="https://www.jsoftware.com/papers/apldisplay.js" type="text/javascript"></script></p> </font> <table> <tr><td><font size="-1">created: </font></td><td><font size="-1">2008-07-18 07:15</font></td></tr> <tr><td><font size="-1">updated:</font></td><td><font size="-1">2017-11-07 17:20</font></td></tr> </table> </td></tr></table> <br><br><br> </body> </html>