Anonymous Functions/Operators/Hyperators: Difference between revisions

From NARS2000
Jump to navigationJump to search
No edit summary
 
(27 intermediate revisions by 3 users not shown)
Line 1: Line 1:
Anonymous functions and operators (AFOs) are a one-line grouping of one or more statements all enclosed in braces such as <apll>{(+⌿⍵)÷≢⍵}</apll>.  This syntax is useful for one-line functions and operators to complement the existing definition types of [[User-Defined_Functions/Operators|user-defined]]:  <apll>∇ Z←avg R</apll>, [[Trains|trains]]:  <apll>(+⌿ ÷ ≢)</apll>, and derived:  <apll>,∘⍋∘⍋∘,</apll>.
Anonymous functions, operators, and hyperators (AFOHs) are a one- or multi-line grouping of one or more statements all enclosed in braces such as <apll>{(+⌿⍵)÷≢⍵}</apll>.  This syntax is useful for one- or multi-line functions, operators, and hyperators to complement the existing definition types of [[User-Defined_Functions/Operators/Hyperators|user-defined]]:  <apll>∇ Z←avg R</apll>, [[Trains|trains]]:  <apll>(+⌿ ÷ ≢)</apll>, and derived:  <apll>,∘⍋∘⍋∘,</apll>.


These objects may be named as in <apll>avg←{(+⌿⍵)÷≢⍵}</apll>, and named or unnamed may be used in place of any APL function (primitive, operator operand, derived, train, user-defined) including within another AFO.
These objects may be named as in <apll>avg←{(+⌿⍵)÷≢⍵}</apll>, and named or unnamed may be used in place of any APL function (primitive, operator operand, hyperator hyperand, derived, train, user-defined) including within another AFOH.


Normally, the statements within the braces execute one by one from left to right, just as in execute.  Execution of the AFO terminates on the first occurrence of one of the following:
== Function Arguments ==


* A [[#Guards|Guard]] with a TRUE condition (see below),
To define an anonymous '''function''', use <apll>⍺</apll> as the name of the (optional) left argument, <apll>∇</apll> as the name of the (optional) anonymous function (for [[#Recursion|recursion]] only), <apll>⍵</apll> as the name of the (optional) right argument, and <apll>χ</apll> as the name of the (optional) Axis Operator.  For example,
* A non-[[#Shy Results|Shy]] value (see below), or
 
* The rightmost statement.
<apll><pre>
      3 5{√+/⍺ ⍵*2}4 12          ⍝ Pythagorean theorem (Dyadic function)
5 13
      {s←(+/⍵)÷2 ⋄ √×/s-0,⍵}3 4 5 ⍝ Heron's formula for triangle area (Monadic function)
6
      f←{⎕TS}                    ⍝ Niladic function
      f
2022 4 23 14 11 38 443
      f
2022 4 23 14 11 39 72</pre></apll>
 
== Operator Operands ==
 
To define an anonymous '''operator''', use the above special names along with <apll>⍺⍺</apll> as the name of the left operand, <apll>∇∇</apll> as the name of the (optional) operator (for [[#Recursion|recursion]] only), and <apll>⍵⍵</apll> as the name of the (optional) right operand.  If neither <apll>⍺⍺</apll> nor <apll>⍵⍵</apll> appears as a token between the braces and outside of character constants, then the object is a function, not an operator.  For example,
 
<table cellpadding="0" cellspacing="0" style="border-collapse:  separate; border-spacing:  5em 0px;">
 
<tr>
<td colspan="7">
<apll>opr←{∘.⍺⍺⍨⍳⍵}</apll>
</td>
</tr>
 
<tr>
<td>
<apll>  =opr 4
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1</apll>
</td>


<td>
<apll>  ⌈opr 4
1 2 3 4
2 2 3 4
3 3 3 4
4 4 4 4</apll>
</td>


<h3>Function Arguments</h3>
<td>
<apll>  *opr 4
1  1  1  1
2  4  8  16
3  9 27  81
4 16 64 256</apll>
</td>


To define an anonymous function, use <apll></apll> as the (optional) left argument, <apll></apll> as the name of the anonymous function (for [[#Recursion|recursion]]), and <apll></apll> as the name of the right argument.  For example,
<td>
<apll>   ≤opr 4
1 1 1 1
0 1 1 1
0 0 1 1
0 0 0 1</apll>
</td>
</tr>
</table>


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3{√+/⍺ ⍵*2}4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ⍝ Pythagorean theorem<br />
In the above examples, the functions <apll> = ⌈ * </apll> are the Left Operands to the Operator <apll>opr</apll>.
5<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{s←(+/⍵)÷2 ⋄ √×/s-0,⍵}3 4 5 ⍝ Heron's formula for triangle area<br />  
6</apll>


<h3>Operator Operands</h3>
== Hyperator Hyperands ==


To define an anonymous operator, use the above special names along with <apll>⍺⍺</apll> as the name of the left operand, <apll>∇∇</apll> as the name of the operator (for [[#Recursion|recursion]]), and <apll>⍵⍵</apll> as the name of the right operand.  If neither <apll>⍺⍺</apll> nor <apll>⍵⍵</apll> appears as a token between the braces and outside of character constants, then the object is a function, not an operator.  For example,
To define an anonymous '''hyperator''', use the above special names along with <apll>⍺⍺⍺</apll> as the name of the left hyperand, <apll>∇∇∇</apll> as the name of the (optional) hyperator (for [[#Recursion|recursion]] only), and <apll>⍵⍵⍵</apll> as the name of the (optional) right hyperand.  If neither <apll>⍺⍺⍺</apll> nor <apll>⍵⍵⍵</apll> appears as a token between the braces and outside of character constants, then the object is a function or operator, not a hyperator.  For example,


<table cellpadding="0" cellspacing="0" style="border-collapse:  separate; border-spacing:  5em 0px;">
<table cellpadding="0" cellspacing="0" style="border-collapse:  separate; border-spacing:  5em 0px;">
Line 27: Line 75:
<tr>
<tr>
<td colspan="7">
<td colspan="7">
<apll>f←{∘.⍺⍺⍨⍳⍵}</apll>
<apll>hyp←{⍺⍺ ⍺⍺⍺⍨⍳⍵}</apll>
</td>
</td>
</tr>
</tr>
Line 33: Line 81:
<tr>
<tr>
<td>
<td>
<apll>&nbsp;&nbsp;&nbsp;=f 4<br />
<apll>   =∘.hyp 4
1 0 0 0<br />
1 0 0 0
0 1 0 0<br />
0 1 0 0
0 0 1 0<br />
0 0 1 0
0 0 0 1</apll>
0 0 0 1</apll>
</td>
</td>


<td>
<td>
<apll>&nbsp;&nbsp;&nbsp;⌈f 4<br />
<apll>   ⌈∘.hyp 4
1 2 3 4<br />
1 2 3 4
2 2 3 4<br />
2 2 3 4
3 3 3 4<br />
3 3 3 4
4 4 4 4</apll>
4 4 4 4</apll>
</td>
</td>


<td>
<td>
<apll>&nbsp;&nbsp;&nbsp;*f 4<br />
<apll>   *∘.hyp 4
1&nbsp; 1&nbsp; 1&nbsp;&nbsp; 1<br />
1 1 1   1
2&nbsp; 4&nbsp; 8&nbsp; 16<br />
2 4 8 16
3&nbsp; 9 27&nbsp; 81<br />
3 9 27 81
4 16 64 256</apll>
4 16 64 256</apll>
</td>
</td>


<td>
<td>
<apll>&nbsp;&nbsp;&nbsp;≤f 4<br />
<apll>   ≤∘.hyp 4
1 1 1 1<br />
1 1 1 1
0 1 1 1<br />
0 1 1 1
0 0 1 1<br />
0 0 1 1
0 0 0 1</apll>
0 0 0 1</apll>
</td>
</td>
Line 66: Line 114:
</table>
</table>


<h3>Ambivalent AFOs</h3>
In the above examples, the Monadic Operator <apll>∘.</apll> is the Left Hyperand and the functions <apll> = ⌈ * ≤ </apll> are the Left Operands to the Hyperator <apll>hyp</apll>.
 
== Ambivalent AFOHs ==
 
User-defined functions/operators/hyperators allow you to specify in their headers that the left argument is optional by enclosing it in braces, as in <apll>∇ Z←{L} foo R</apll>, and to test for the presence or absence of the optional argument using <apll>0=⎕NC 'L'</apll>.


User-defined functions/operators allow you to specify in their headers that the left argument is optional by enclosing it in braces, as in <apll>∇ Z←{L} foo R</apll>.  This behavior is also available to AFOs by including a statement that assigns a value to <apll>⍺</apll>.  If <apll>⍺</apll> does not have a value when that statement is encountered, the statement is executed; otherwise, that entire statement is ignored including any side effects.  This behavior obviates the need to use <apll>0=⎕NC '⍺'</apll> to test for a value in <apll>⍺</apll>.
This behavior is also available to AFOHs by including a statement that assigns a value to <apll>⍺</apll>.  If <apll>⍺</apll> does not have a value when that statement is encountered, the statement is executed; otherwise, that entire statement is ignored including any side effects.  This behavior obviates the need to use <apll>0=⎕NC '⍺'</apll> to test for a value in <apll>⍺</apll>.  It also means that as a consequence of this rule, regardless of how the AFOH is called, any second or subsequent statements that assign a value to <apll>⍺</apll> are always ignored.


For example,
For example,


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f←{⍺←2 ⋄ ⍺√⍵}<br />
<apll><pre>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f 16<br />
      f←{⍺←2 ⋄ ⍺√⍵}
4<br />
      f 16
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3 f 27<br />
4
3<br />
      3 f 27
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f←{⎕←⍺←⍵ ⋄ (⍳⍺)∘.⍺⍺⍳⍵}<br />
3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;⌊f 4<br />
      f←{⎕←⍺←⍵ ⋄ (⍳⍺)∘.⍺⍺⍳⍵}
4<br />
      ⌊f 4
1 1 1 1<br />
4
1 2 2 2<br />
1 1 1 1
1 2 3 3<br />
1 2 2 2
1 2 3 4<br />
1 2 3 3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3⌊f 4<br />
1 2 3 4
1 1 1 1<br />
      3⌊f 4
1 2 2 2<br />
1 1 1 1
1 2 3 3</apll>
1 2 2 2
1 2 3 3
      f←{⎕←⍺←9 ⋄ ⎕←⍺←0 ⋄ ⍺+⍵}
      4 f 12 ⍝ Both assignments of ⍺ ignored
16
      f 12  ⍝ Second assignment of ⍺ ignored
9
21</pre></apll>
 
== Axis Operator ==


As a consequence of this rule, regardless of whether the AFO is called monadically or dyadically, any second or subsequent statements that assign a value to <apll></apll> are always ignored.
Just as with [[User-Defined Functions/Operators/Hyperators]], Anonymous Functions/Operators/Hyperators can accept an optional Axis Operator via the <apll>χ</apll> symbol (Alt-Shift-'c' or Ctrl-Shift-'c' depending upon your keyboard layout).  Also, in a manner similar to the optional left argument for Ambivalent AFOHs (see above), a default value for the Axis Operator may be assigned in case the caller doesn't provide one; if the user provides a value for the Axis Operator, the statement which assigns <apll>χ</apll> is ignored.
<apll><pre>      avg←{χ←⎕IO ⋄ (+/[χ] ⍵)÷≢⍵}
      avg 1 2 3
2
      avg 2 3⍴⍳6
2.5 3.5 4.5
      avg[1] 2 3⍴⍳6
2.5 3.5 4.5
      avg[2] 2 3⍴⍳6
3 7.5     
      avg[⍬] 23
23
      avg 23
AXIS ERROR
      avg 23
      ∧
</pre></apll>
Because the chosen default for the Axis Operator isn't appropriate for scalars, the above function may be modified to handle that case:
<apll><pre>      avg←{χ←(0≠⍴⍴⍵)/⎕IO ⋄ (+/[χ] ⍵)÷≢⍵}
      avg 23
23</pre></apll>
This feature was first seen in [https://www.gnu.org/software/apl/apl.html#Section-2_002e7 GNU APL].


<h3>Valences</h3>
== Valences ==


An AFO may be
An AFOH may be


* Ambivalent (must be called with either one or two arguments),
* Ambivalent (must be called with either one or two arguments),
Line 102: Line 184:
depending upon which of the special symbols are present in its definition.
depending upon which of the special symbols are present in its definition.


Disregarding special symbols inside of character constants
Disregarding special symbols inside of character constants and/or comments
 
* For anonymous functions (and operators/hyperators):
** If <apll>⍺←</apll> appears as a sequence of tokens, then the (derived) function is ambivalent,
** Otherwise, if <apll>⍺</apll> appears as a token, the (derived) function is dyadic,
** Otherwise, if <apll>⍵</apll> appears as a token, the (derived) function is monadic,
** Otherwise, if neither <apll>⍺</apll> nor <apll>⍵</apll> appears as a token, the (derived) function is niladic.
* For anonymous operators only:
** If <apll>⍵⍵</apll> appears as a token, the operator is dyadic (must be called with two operands &mdash; left and right),
** Otherwise, if <apll>⍺⍺</apll> appears as a token, the operator is monadic (must be called with one operand &mdash; left only).
* For anonymous hyperators only:
** If <apll>⍵⍵⍵</apll> appears as a token, the hyperator is dyadic (must be called with two hyperands &mdash; left and right),
** Otherwise, if <apll>⍺⍺⍺</apll> appears as a token, the hyperator is monadic (must be called with one hyperand &mdash; left only).


*For anonymous functions (and operators):
For example,
** If <apll>⍺←</apll> appears as a sequence of tokens, then the object is an ambivalent (derived) function,
** Otherwise, if <apll>⍺</apll> appears as a token, the object is a dyadic (derived) function,
** Otherwise, if <apll>⍵</apll> appears as a token, the object is a monadic (derived) function,
** Otherwise, if neither <apll>⍺</apll> nor <apll>⍵</apll> appears as a token, the object is a niladic (derived) function.
*For anonymous operators:
** If <apll>⍵⍵</apll> appears as a token, the operator is dyadic (must be called with a left and right operand),
** Otherwise, it is monadic (must be called with a left operand only).


For the moment, the case of a niladic derived function from either a monadic or dyadic operator signals a <apll>SYNTAX ERROR</apll>.
<apll><pre>
      {⍵}2
2
      1{⍵}2
VALENCE ERROR
      1{⍵}2
      ^
      1{⍺+⍵}2
3
      {⍺+⍵}2
VALENCE ERROR
      {⍺+⍵}2
      ∧
      {⍺←2 ⋄ ⍺+⍵}2&nbsp;&nbsp;⍝ Ambivalent function, monadic with default left argument 2
4
      3{⍺←2 ⋄ ⍺+⍵}2&nbsp;⍝ Ambivalent function, dyadic with left argument 3
5
      {⍳3}          ⍝ A three-element simple vector
1 2 3
      {⍳3}23        ⍝ A two-element nested vector
1 2 3  23
      12{⍳3}23      ⍝ A three-element nested vector
12  1 2 3  23
      3{∘.=⍨⍳⍺⍺}    ⍝ A niladic derived function from a monadic operator
1 0 0
0 1 0
0 0 1</pre></apll>


For example,
== Multi-Line AFOHs ==


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{⍵}2<br />
An AFOH may be defined on multiple lines (just like User-Defined Functions/Operators/Hyperators) by first naming it (e.g. <apll>h←{s←(+/⍵)÷2 ⋄ √×/s-0,⍵}</apll>), and then editing it in the usual way (e.g., <apll>∇h</apll>). For more details, see [[Function_Editing|Function Editing]].
2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1{⍵}2<br />
VALENCE ERROR<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1{⍵}2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1{+⍵}2<br />
3<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{⍺+}2<br />
VALENCE ERROR<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{⍺+⍵}2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;∧<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{⍺←2 ⋄ ⍺+⍵}2&nbsp;&nbsp;⍝ Ambivalent function, monadic with default left argument 2<br />
4<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3{⍺←2 ⋄ ⍺+⍵}2&nbsp;⍝ Ambivalent function, dyadic with left argument 3<br />
5<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{⍳3}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;⍝ A three-element simple vector<br />
1 2 3<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{⍳3}23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;⍝ A two-element nested vector<br />
&nbsp;1 2 3&nbsp; 23<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;12{⍳3}23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;⍝ A three-element nested vector<br />
&nbsp;12&nbsp; 1 2 3&nbsp; 23<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3{∘.=⍨⍳⍺⍺}&nbsp;&nbsp;&nbsp;&nbsp;⍝ A niladic derived function from a monadic operator<br />
SYNTAX ERROR<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3{∘.=⍨⍳⍺⍺}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;∧</apll>


<h3>Guards</h3>
== Guards ==


Guards are used to test for a condition and execute a statement or not depending upon the value of the conditional expression.  This behavior is identical to the [[Control_Structures|control structure]]
[http://en.wikipedia.org/wiki/Guard_%28computer_science%29 Guards] are used to test for a condition and execute a statement or not depending upon the value of the conditional expression.  This behavior is identical to the [[Control_Structures|control structure]]


<apll>:if Cond ⋄ CondStmt ⋄ :return ⋄ :end</apll>
<apll>:if Cond ⋄ CondStmt ⋄ :return ⋄ :end</apll>
Line 152: Line 240:
Guards appear as a Boolean-valued APL expression (<apll>Cond</apll>) followed by a colon, followed by a single APL statement (<apll>CondStmt</apll>) as in
Guards appear as a Boolean-valued APL expression (<apll>Cond</apll>) followed by a colon, followed by a single APL statement (<apll>CondStmt</apll>) as in


<apll>{... ⋄ Cond:CondStmt ⋄ ....}</apll>
<apll>{... ⋄ Cond:CondStmt ⋄ ...}</apll>


which executes <apll>CondStmt</apll> and terminates the AFO if and only if <apll>Cond</apll> evaluates to TRUE (<apll>1</apll>).
which executes <apll>CondStmt</apll> and terminates the AFOH if and only if <apll>Cond</apll> evaluates to TRUE (<apll>1</apll>).


For example,
For example,


<apll>{... ⋄ 0∊⍴⍵:'empty right argument' ⋄ ....}</apll>
<apll>{... ⋄ 0∊⍴⍵:'empty right argument' ⋄ ...}</apll>


As many guard statements may appear in an AFO as desired.  They are executed in turn until one of them evaluates to TRUE, at which time the statement following the colon is executed and the function terminates with the result of that conditional statement as the result of the AFO.
As many guard statements may appear in an AFOH as desired.  They are executed in turn until one of them evaluates to TRUE, at which time the statement following the colon is executed and the function terminates with any result of that conditional statement as the result of the AFOH.


If <apll>Cond</apll> does not evaluate to a Boolean-valued scalar or one-element vector, a <apll>RANK</apll>, <apll>LENGTH</apll>, or <apll>DOMAIN ERROR</apll> is signalled, as appropriate.
If <apll>Cond</apll> does not evaluate to a Boolean-valued scalar or one-element vector, a <apll>RANK</apll>, <apll>LENGTH</apll>, or <apll>DOMAIN ERROR</apll> is signalled, as appropriate.


If the rightmost statement is executed and it is a guard statement whose <apll>Cond</apll> evaluates to FALSE (<apll>0</apll>), the AFO terminates with no value; if the result of that AFO is assigned, a <apll>VALUE ERROR</apll> is signalled.
If the rightmost statement is executed and it is a guard statement whose <apll>Cond</apll> evaluates to FALSE (<apll>0</apll>), the AFOH terminates with no value; if the result of that AFOH is assigned, a <apll>VALUE ERROR</apll> is signalled.
 
== Chaining Guards ==
 
If the <apll>Cond</apll> in a Guard statement evaluates to TRUE, the next statement may be another Guard statement, and so forth, each of which further reduces the likelihood of evaluating <apll>CondStmt</apll>.  For example,
 
<apll>{Cond1: Cond2: Cond3: ... CondStmt ⋄ ...}</apll>


<h3>Shy Results</h3>
The effect of chaining several Guard statements together is to evaluate each <apll>Cond</apll> from Left-to-Right, and as soon as one of the <apll>Cond</apll>s evaluates to FALSE, evaluation of the remainder of <apll>Cond</apll>s stops and the <apll>CondStmt</apll> is skipped.  Only if all <apll>Cond</apll>s are TRUE is <apll>CondStmt</apll> executed.


A "shy" result is any result that doesn't automatically display its value, a simple example of which is <apll>L←⍳3</apll>:  the result is <apll>⍳3</apll> (as evidenced by the extension to <apll>3+L←⍳3</apll>), but because it has been assigned to a name, the result doesn't automatically display.  Other ways to produce a shy result are to use the [[Sink]] syntax <apll>←⍳3</apll>, or to call a [[User-Defined_Functions/Operators#Shy|user-defined function]] that declares in its header that the result is shy as in <apll>∇ {Z}←foo R</apll>.
Outside of Anonymous Functions, this syntax is equivalent to joining the <apll>Cond</apll>s with <apll>:andif</apll>s as in


A shy result propagates up the chain of results just as it does through the Execute primitive.  That is, if the last statement executed has a shy result, the result of execute is shy, too.
<apll>:if Cond1 ⋄ :andif Cond2 ⋄ :andif Cond3 ⋄ ... ⋄ CondStmt ⋄ :return ⋄ :end</apll>
 
Compare this with
 
<apll>:if Cond1 ∧ Cond2 ∧ Cond3 ... ⋄ CondStmt ⋄ :return ⋄ :end</apll>
 
which has the (undesired) effect evaluating all of the <apll>Cond</apll>s (from Right-to-Left!) even if an early <apll>Cond</apll> evaluates to FALSE.
 
For example, to test for a Simple Positive Even Scalar Number,
 
<apll><pre>
      f←{0=≡⍵: 0 0≡⊤0,⍵: 0<⍵: 0=2|⍵: 'Oui' ⋄ 'Non'}
      f¨12 ¯12 (,12) 33 34 'A' 1r1 2r1 0r1 0v 1.1v 2v
Oui Non Non Non Oui Non Non Oui Non Non Non Oui
</pre></apll>
 
== Shy Results ==
 
A "shy" result is any result that doesn't automatically display its value, a simple example of which is <apll>L←⍳3</apll>:  the result is <apll>⍳3</apll> (as evidenced by the extension to <apll>3+L←⍳3</apll>), but because it has been assigned to a name, the result doesn't automatically display.  Other ways to produce a shy result are to use the [[Sink]] syntax <apll>←⍳3</apll>, or to call a [[User-Defined_Functions/Operators/Hyperators#Shy|user-defined function]] that declares in its header that the result is shy as in <apll>∇ {Z}←foo R</apll>.
 
A shy result propagates up the chain of results just as it does through the Execute primitive.  That is, if the last statement executed has a shy result, the result of Execute is shy, too.


Typically, <apll>⎕←</apll> is used to expose a shy result.
Typically, <apll>⎕←</apll> is used to expose a shy result.


AFOs also may have shy results by virtue of the final result being
AFOHs also may have shy results by virtue of the final result being
* [[Sink|Sinked]],
* [[Sink|Sinked]],
* Assigned to a name, or
* Assigned to a name, or
Line 181: Line 295:
For example,
For example,


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{←⍳3}<br />
<apll><pre>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;⎕←{←⍳3}<br />
      {←⍳3}
1 2 3<br />
      ⎕←{←⍳3}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{L←⍳3}<br />
1 2 3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;⎕←{L←⍳3}<br />
      {L←⍳3}
1 2 3</apll>
      ⎕←{L←⍳3}
1 2 3</pre></apll>


Ordinarily, a shy result doesn't terminate the AFO, as in
Ordinarily, a shy result doesn't terminate the AFOH, as in


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{←⍳3 ⋄ 'abc'}<br />
<apll><pre>
abc</apll>
      {←⍳3 ⋄ 'abc'}
abc</pre></apll>


To force termination, precede the assignment with a guard as in
To force termination, precede the assignment with a guard as in
Line 199: Line 315:
which terminates with a shy result in all three cases.
which terminates with a shy result in all three cases.


<h3>Localization</h3>
== Localization ==


Unlike user-defined functions, in AFOs all names to which an assignment is made are automatically localized.  As a result, a direct assignment inside an AFO cannot affect the value of a name defined higher up in the execution chain '''unless''' it is made via a user-defined function or execute as in
Unlike user-defined functions, in AFOHs all names to which an assignment is made are automatically localized.  As a result, a direct assignment inside an AFOH cannot affect the value of a name defined higher up in the execution chain '''unless''' it is made via a user-defined function or the Execute primitive as in


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L←⍳9 ⋄ {L←"abc" ⋄ ⍵}23<br />
<apll><pre>
23<br />
      L←⍳9 ⋄ {L←"abc" ⋄ ⍵}23
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L<br />
23
1 2 3 4 5 6 7 8 9<br />
      L
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L←⍳9 ⋄ {⍎'L←"abc"' ⋄ ⍵}23<br />
1 2 3 4 5 6 7 8 9
23<br />
      L←⍳9 ⋄ {⍎'L←"abc"' ⋄ ⍵}23
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L<br />
23
abc</apll>
      L
abc</pre></apll>


<h3>Scoping</h3>
== Scoping ==


When calls to user-defined functions are nested, a reference to a name by an inner function is resolved by looking up the chain of nested functions for the nearest level at which that name is localized.  Looked at from a different perspective, when a name is localized to a function, its scope comprises all functions called by that function.  This is called '''dynamic scoping'''.
When calls to user-defined functions are nested, a reference to a name by an inner function is resolved by looking up the chain of nested functions for the nearest level at which that name is localized.  Looked at from a different perspective, when a name is localized to a function, its scope consists of all functions called by that function.  This is called '''dynamic scoping'''.


AFOs use a different mechanism where names referenced by an AFO are resolved by the context in which the AFO is defined, not where it is used.  This is called '''lexical scoping''' or '''static scoping'''.
AFOHs use a different mechanism where names referenced by an AFOH are resolved by the context in which the AFOH is defined, not where it is used.  This is called '''lexical scoping''' or '''static scoping'''.


In other words, according to [http://en.wikipedia.org/wiki/Scope_%28computer_science%29#Lexical_scoping_and_dynamic_scoping Wikipedia], "This means that if function <apll>f</apll> invokes a separately defined function <apll>g</apll>, then under lexical scoping, function <apll>g</apll> does not have access to <apll>f</apll>'s local variables (since the text of <apll>g</apll> is not inside the text of <apll>f</apll>), while under dynamic scoping, function <apll>g</apll> does have access to <apll>f</apll>'s local variables (since the invocation of <apll>g</apll> is inside the invocation of <apll>f</apll>)".
In other words, to paraphrase [http://en.wikipedia.org/wiki/Scope_%28computer_science%29#Lexical_scoping_and_dynamic_scoping Wikipedia], "This means that if function <apll>f</apll> invokes function <apll>g</apll> that is defined outside the context of <apll>f</apll>, then under lexical scoping, function <apll>g</apll> does not have access to <apll>f</apll>'s local variables (since the definition of <apll>g</apll> is not inside the definition of <apll>f</apll>), while under dynamic scoping, function <apll>g</apll> does have access to <apll>f</apll>'s local variables (since the invocation of <apll>g</apll> is inside the invocation of <apll>f</apll>)".


For example,
For example,


<apll>
<apll><pre>
&nbsp;&nbsp;&nbsp;&nbsp;∇ foo;f;g;a<br />
    ∇ foo;f g a
[1]&nbsp;&nbsp;&nbsp;a←'static'<br />
[1]   a←'static'
[2]&nbsp;&nbsp;&nbsp;←⎕fx 'f R;a' 'a←"dynamic"' 'g R'<br />
[2]   ←⎕fx 'f R;a' 'a←"dynamic"' 'g R'
[3]&nbsp;&nbsp;&nbsp;←⎕fx 'g R' '"scope ←→ ",a'<br />
[3]   ←⎕fx 'g R' '"scope ←→ ",a'
[4]&nbsp;&nbsp;&nbsp;f 'a'<br />
[4]   f 'a'
&nbsp;&nbsp;&nbsp;&nbsp;<br />
   
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foo<br />
scope ←→ dynamic<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{a←'static' ⋄ f←{a←'dynamic' ⋄ g ⍵} ⋄ g←{"scope ←→ ",a ⋄ ⍵} ⋄ f 'a'}<br />
scope ←→ static<br />
</apll>


<h3>Recursion</h3>
      foo
scope ←→ dynamic
      {a←'static' ⋄ f←{a←'dynamic' ⋄ g ⍵} ⋄ g←{'scope ←→ ',a ⋄ ⍵} ⋄ f 'a'}
scope ←→ static
</pre></apll>


AFOs may be called recursively, but because they might be unnamed (i.e., anonymous), we use the <apll>∇</apll> symbol as the name of the AFO.
== Recursion ==
 
AFOHs may be called recursively, but because they might be unnamed (i.e., anonymous), the <apll>∇</apll> symbol is used to name the AFOH.


For example, with anonymous functions,
For example, with anonymous functions,


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{⍺←10 ⋄ ⍺=1:⍵ ⋄ (⍺-1)∇⍵,+/¯2↑⍵}1&nbsp;&nbsp;&nbsp;⍝ 10-element Fibonacci sequence<br />
<apll><pre>
1 1 2 3 5 8 13 21 34 55<br />
      ⍝ Fibonacci sequence algorithm
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;20{⍺←10 ⋄ ⍺=1:⍵ ⋄ (⍺-1)∇⍵,+/¯2↑⍵}1 ⍝ 20-element Fibonacci sequence<br />
      f←{⍺←10 ⋄ ⍺=1:⍵ ⋄ (⍺-1)∇⍵,+/¯2↑⍵}
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765<br />
      f 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;12 {⍺=0:⍵ ⋄ (⍵|⍺)∇⍺} 8 ⍝ Euclidean algorithm for Greatest Common Divisor<br />
1 1 2 3 5 8 13 21 34 55
4</apll>
      20 f 1
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
      ⍝ Euclidean algorithm for Greatest Common Divisor
      12 {⍺=0:|⍵ ⋄ (⍵|⍺)∇⍺} 8
4</pre></apll>
 
With anonymous operators,
 
{|
|-
|* <apll>∇</apll>  || references the operator with its operand(s) already bound  || (that is, <apll>∇</apll>  || references the entire derived function)
|-
|* <apll>∇∇</apll>  || references the operator with its operand(s) not bound || (that is, <apll>∇∇</apll> || references the operator itself)
|}
 
That is,
 
{|
|-
|* for monadic || anonymous operators || <apll>∇ ←→ ⍺⍺∇∇</apll>
|-
|* for dyadic  || anonymous operators || <apll>∇ ←→ ⍺⍺∇∇⍵⍵</apll>
|}
 
With anonymous hyperators,
 
{|
|-
|* <apll>∇</apll>  || references the hyperator with both its hyperand(s) and operand(s) already bound || (that is, <apll>∇</apll> || references the entire derived function)
|-
|* <apll>∇∇</apll>  || references the hyperator with just its hyperand(s) bound  || (that is, <apll>∇∇</apll> || references the operator part of the hyperator)
|-
|* <apll>∇∇∇</apll> || references the hyperator with neither its hyperand(s) nor operand(s) bound || (that is, <apll>∇∇∇</apll> || references the hyperator itself)
|}
 
That is,


With anonymous operators, <apll>∇</apll> references the derived function with its operand(s) already bound, and <apll>∇∇</apll> references the operator itself with its operand(s) yet to be bound.  That is, for monadic anonymous operators <apll>∇ ←→ ⍺⍺∇∇</apll>, and for dyadic anonymous operators <apll>∇ ←→ ⍺⍺∇∇⍵⍵</apll>.
{|
|-
|* for anonymous monadic || hyperand monadic || operand hyperators, &nbsp; &nbsp; || <apll>∇ ←→ ⍺⍺∇∇  ←→ ⍺⍺ ⍺⍺⍺∇∇∇</apll>
|-
|* for anonymous monadic || hyperand dyadic  || operand hyperators, &nbsp; &nbsp; || <apll>∇ ←→ ⍺⍺∇∇⍵⍵ ←→ ⍺⍺ ⍺⍺⍺∇∇∇⍵⍵</apll>
|-
|* for anonymous dyadic  || hyperand monadic || operand hyperators, &nbsp; &nbsp; || <apll>∇ ←→ ⍺⍺∇∇   ←→ ⍺⍺ ⍺⍺⍺∇∇∇⍵⍵⍵</apll>
|-
|* for anonymous dyadic  || hyperand dyadic || operand hyperators, &nbsp; &nbsp; || <apll>∇ ←→ ⍺⍺∇∇⍵⍵ ←→ ⍺⍺ ⍺⍺⍺∇∇∇⍵⍵⍵ ⍵⍵</apll>
|}


For example, with anonymous operators,
For example, with anonymous operators,


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f←{0=⍴⍵:⍺⍺/0⍴⍵ ⋄ 1=⍴⍵:⊂↑⍵ ⋄ ⊂(↑⍵)⍺⍺ ⊃∇1↓⍵} ⍝ Definition of vector reduction<br />
<apll><pre>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+f⍳4<br />
      ⍝ Generalized definition of vector reduction
10<br />
      f←{0=⍴⍵:⍺⍺/0⍴⍵ ⋄ 1=⍴⍵:⊂↑⍵ ⋄ ⊂(↑⍵)⍺⍺ ⊃∇1↓⍵}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;×f⍳4<br />
      +f⍳4
24</apll>
10
      ×f⍳4
24
      +f(1 2)(3 4)
4 6</pre></apll>


A more advanced example of recursion of an anonymous operator is [http://en.wikipedia.org/wiki/Hyperoperation hyperoperation] expressed below as a monadic operator where its operand <apll>N</apll> indexes successively more powerful functions as derived functions:
A more advanced example of recursion of an anonymous operator is [http://en.wikipedia.org/wiki/Hyperoperation hyperoperation] expressed below as a monadic operator where its operand <apll>N</apll> indexes successively more powerful functions as derived functions:
Line 267: Line 432:
* <apll>N=5</apll> is the [http://en.wikipedia.org/wiki/Pentation pentation] function, i.e. the tetration function on <apll>⍺</apll> repeated <apll>⍵</apll> times,
* <apll>N=5</apll> is the [http://en.wikipedia.org/wiki/Pentation pentation] function, i.e. the tetration function on <apll>⍺</apll> repeated <apll>⍵</apll> times,
* etc.
* etc.
written on multiple lines for clarity:
written on multiple lines using [[Function_Editing|Line Continuations]] for clarity:
 
<apll><pre>
  ho←{⍺⍺=0    :⍵+1
<span style="color:blue;">➥</span>&nbsp;⋄ (⍺⍺=1)∧⍵=0:⍺
<span style="color:blue;">➥</span>&nbsp;⋄ (⍺⍺=2)∧⍵=0:0
<span style="color:blue;">➥</span>&nbsp;⋄ (⍺⍺≥3)∧⍵=0:1
<span style="color:blue;">➥</span>&nbsp;⋄ ⍺ ((⍺⍺-1)∇∇) ⍺∇⍵-1}
 
      2 (0 ho) 5 ⍝ Successor:  1+5 (left argument ignored)
6
      2 (1 ho) 5 ⍝ Addition:  2+5
7
      2 (2 ho) 5 ⍝ Multiplication:  2×5
10
      2 (3 ho) 5 ⍝ Exponentiation:  2*5
32
      2 (4 ho) 5 ⍝ Tetration:  */5⍴2
200352993040684646497907235156025575044782547556975141926501697371089405955...</pre></apll>


<apll>
Computing <apll>*/5⍴2<_x/></apll> takes but a fraction of a second and returns a number with 19,729 digits!
ho←{⍺⍺=0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:⍵+1<br />
&nbsp;⋄ (⍺⍺=1)∧⍵=0:⍺<br />
&nbsp;⋄ (⍺⍺=2)∧⍵=0:0<br />
&nbsp;⋄ (⍺⍺≥3)∧⍵=0:1<br />
&nbsp;⋄ ⍺ ((⍺⍺-1)∇∇) ⍺∇⍵-1}
</apll>


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2 (0 ho) 5 ⍝ Successor1+5 (left argument ignored)<br />
'''N.B.:''' All of the <apll></apll>, <apll>∇∇</apll>, and <apll>∇∇∇</apll> names may be used in user-defined recursive functions/operators/hyperators, where they have the same meaning as they do in AFOHs.
6<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2 (1 ho) 5 ⍝ Addition:  2+5<br />
7<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2 (2 ho) 5 ⍝ Multiplication:  2×5<br />
10<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2 (3 ho) 5 ⍝ Exponentiation:  2*5<br />
32</apll>


If we could compute <apll>2x (4 ho) 5x</apll> in a reasonable amount of time, it would return a number with 19,729 digits!
== Termination ==


Both of the <apll>∇</apll> and <apll>∇∇</apll> names may be used in user-defined functions, where they have the same meaning.
Normally, the statements within the braces execute one by one from left to right, just as in the Execute primitive. Execution of the AFOH terminates on the first occurrence of one of the following:


<h3>Restrictions</h3>
* A [[#Guards|Guard]] with a TRUE condition,
* A non-[[#Shy Results|Shy]] value to display, or
* The rightmost statement.


* For the moment, AFOs may be written on one line only.
== Restrictions ==
* As a consequence of the above one-line restriction, AFOs may not contain comments.
 
* Assignments to any of the special names (<apll>∇</apll>, <apll>⍵</apll>, <apll>⍺⍺</apll>, <apll>∇∇</apll>, <apll>⍵⍵</apll>) except for <apll>⍺</apll> are not allowed; they signal a <apll>SYNTAX ERROR</apll>.
* Assignments to any of the special names (<apll>∇</apll>, <apll>⍵</apll>, <apll>⍺⍺</apll>, <apll>∇∇</apll>, <apll>⍵⍵</apll>, <apll>⍺⍺⍺</apll>, <apll>∇∇∇</apll>, <apll>⍵⍵⍵</apll>) except for <apll>⍺</apll> are not allowed; they signal a <apll>SYNTAX ERROR</apll>.
* Assignments to <apll>⍺</apll> within a guard statement are not allowed; they signal a <apll>SYNTAX ERROR</apll>.
* Assignments to <apll>⍺</apll> within a guard statement are not allowed; they signal a <apll>SYNTAX ERROR</apll>.
* None of the special names may be erased, via <apll>⎕EX</apll> or otherwise.
* None of the special names may be erased, via <apll>⎕EX</apll> or otherwise.
* Goto statements (including <apll>→</apll>, <apll>→0</apll>, and <apll>→⍬</apll>) are not allowed; they signal a <apll>SYNTAX ERROR</apll>.
* Goto statements are not allowed; they signal a <apll>SYNTAX ERROR</apll>.
* Control structures such as <apll>:if ... ⋄ ... ⋄ :end</apll> are not allowed; they signal a <apll>SYNTAX ERROR</apll>.
* Control structures (e.g., <apll>:if ... ⋄ ... ⋄ :end</apll>) are not allowed; they signal a <apll>SYNTAX ERROR</apll>.
* Line labels except for [[System_Labels|System Labels]] are not allowed.
 
== Acknowledgements ==
 
This design of this feature was copied (with minor changes) from the same feature designed and implemented by John Scholes and other folks at Dyalog, Inc.

Latest revision as of 14:06, 10 September 2022

Anonymous functions, operators, and hyperators (AFOHs) are a one- or multi-line grouping of one or more statements all enclosed in braces such as {(+⌿⍵)÷≢⍵}. This syntax is useful for one- or multi-line functions, operators, and hyperators to complement the existing definition types of user-defined: ∇ Z←avg R, trains: (+⌿ ÷ ≢), and derived: ,∘⍋∘⍋∘,.

These objects may be named as in avg←{(+⌿⍵)÷≢⍵}, and named or unnamed may be used in place of any APL function (primitive, operator operand, hyperator hyperand, derived, train, user-defined) including within another AFOH.

Function Arguments

To define an anonymous function, use as the name of the (optional) left argument, as the name of the (optional) anonymous function (for recursion only), as the name of the (optional) right argument, and χ as the name of the (optional) Axis Operator. For example,

      3 5{√+/⍺ ⍵*2}4 12           ⍝ Pythagorean theorem (Dyadic function)
5 13
      {s←(+/⍵)÷2 ⋄ √×/s-0,⍵}3 4 5 ⍝ Heron's formula for triangle area (Monadic function)
6
      f←{⎕TS}                     ⍝ Niladic function
      f
2022 4 23 14 11 38 443 
      f
2022 4 23 14 11 39 72

Operator Operands

To define an anonymous operator, use the above special names along with ⍺⍺ as the name of the left operand, ∇∇ as the name of the (optional) operator (for recursion only), and ⍵⍵ as the name of the (optional) right operand. If neither ⍺⍺ nor ⍵⍵ appears as a token between the braces and outside of character constants, then the object is a function, not an operator. For example,

opr←{∘.⍺⍺⍨⍳⍵}

=opr 4 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1

⌈opr 4 1 2 3 4 2 2 3 4 3 3 3 4 4 4 4 4

*opr 4 1 1 1 1 2 4 8 16 3 9 27 81 4 16 64 256

≤opr 4 1 1 1 1 0 1 1 1 0 0 1 1 0 0 0 1

In the above examples, the functions = ⌈ * ≤ are the Left Operands to the Operator opr.

Hyperator Hyperands

To define an anonymous hyperator, use the above special names along with ⍺⍺⍺ as the name of the left hyperand, ∇∇∇ as the name of the (optional) hyperator (for recursion only), and ⍵⍵⍵ as the name of the (optional) right hyperand. If neither ⍺⍺⍺ nor ⍵⍵⍵ appears as a token between the braces and outside of character constants, then the object is a function or operator, not a hyperator. For example,

hyp←{⍺⍺ ⍺⍺⍺⍨⍳⍵}

=∘.hyp 4 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1

⌈∘.hyp 4 1 2 3 4 2 2 3 4 3 3 3 4 4 4 4 4

*∘.hyp 4 1 1 1 1 2 4 8 16 3 9 27 81 4 16 64 256

≤∘.hyp 4 1 1 1 1 0 1 1 1 0 0 1 1 0 0 0 1

In the above examples, the Monadic Operator ∘. is the Left Hyperand and the functions = ⌈ * ≤ are the Left Operands to the Hyperator hyp.

Ambivalent AFOHs

User-defined functions/operators/hyperators allow you to specify in their headers that the left argument is optional by enclosing it in braces, as in ∇ Z←{L} foo R, and to test for the presence or absence of the optional argument using 0=⎕NC 'L'.

This behavior is also available to AFOHs by including a statement that assigns a value to . If does not have a value when that statement is encountered, the statement is executed; otherwise, that entire statement is ignored including any side effects. This behavior obviates the need to use 0=⎕NC '⍺' to test for a value in . It also means that as a consequence of this rule, regardless of how the AFOH is called, any second or subsequent statements that assign a value to are always ignored.

For example,

      f←{⍺←2 ⋄ ⍺√⍵}
      f 16
4
      3 f 27
3
      f←{⎕←⍺←⍵ ⋄ (⍳⍺)∘.⍺⍺⍳⍵}
      ⌊f 4
4
1 1 1 1
1 2 2 2
1 2 3 3
1 2 3 4
      3⌊f 4
1 1 1 1
1 2 2 2
1 2 3 3
      f←{⎕←⍺←9 ⋄ ⎕←⍺←0 ⋄ ⍺+⍵}
      4 f 12 ⍝ Both assignments of ⍺ ignored
16
      f 12   ⍝ Second assignment of ⍺ ignored
9
21

Axis Operator

Just as with User-Defined Functions/Operators/Hyperators, Anonymous Functions/Operators/Hyperators can accept an optional Axis Operator via the χ symbol (Alt-Shift-'c' or Ctrl-Shift-'c' depending upon your keyboard layout). Also, in a manner similar to the optional left argument for Ambivalent AFOHs (see above), a default value for the Axis Operator may be assigned in case the caller doesn't provide one; if the user provides a value for the Axis Operator, the statement which assigns χ is ignored.

      avg←{χ←⎕IO ⋄ (+/[χ] ⍵)÷≢⍵}
      avg 1 2 3
2
      avg 2 3⍴⍳6
2.5 3.5 4.5 
      avg[1] 2 3⍴⍳6
2.5 3.5 4.5 
      avg[2] 2 3⍴⍳6
3 7.5      
      avg[⍬] 23
23
      avg 23
AXIS ERROR
      avg 23
      ∧

Because the chosen default for the Axis Operator isn't appropriate for scalars, the above function may be modified to handle that case:

      avg←{χ←(0≠⍴⍴⍵)/⎕IO ⋄ (+/[χ] ⍵)÷≢⍵}
      avg 23
23

This feature was first seen in GNU APL.

Valences

An AFOH may be

  • Ambivalent (must be called with either one or two arguments),
  • Dyadic (must be called with two arguments),
  • Monadic (must be called with one argument), or
  • Niladic (must be called with no arguments),

depending upon which of the special symbols are present in its definition.

Disregarding special symbols inside of character constants and/or comments

  • For anonymous functions (and operators/hyperators):
    • If ⍺← appears as a sequence of tokens, then the (derived) function is ambivalent,
    • Otherwise, if appears as a token, the (derived) function is dyadic,
    • Otherwise, if appears as a token, the (derived) function is monadic,
    • Otherwise, if neither nor appears as a token, the (derived) function is niladic.
  • For anonymous operators only:
    • If ⍵⍵ appears as a token, the operator is dyadic (must be called with two operands — left and right),
    • Otherwise, if ⍺⍺ appears as a token, the operator is monadic (must be called with one operand — left only).
  • For anonymous hyperators only:
    • If ⍵⍵⍵ appears as a token, the hyperator is dyadic (must be called with two hyperands — left and right),
    • Otherwise, if ⍺⍺⍺ appears as a token, the hyperator is monadic (must be called with one hyperand — left only).

For example,

      {⍵}2
2
      1{⍵}2
VALENCE ERROR
      1{⍵}2
       ^
      1{⍺+⍵}2
3
      {⍺+⍵}2
VALENCE ERROR
      {⍺+⍵}2
      ∧
      {⍺←2 ⋄ ⍺+⍵}2  ⍝ Ambivalent function, monadic with default left argument 2
4
      3{⍺←2 ⋄ ⍺+⍵}2 ⍝ Ambivalent function, dyadic with left argument 3
5
      {⍳3}          ⍝ A three-element simple vector
1 2 3
      {⍳3}23        ⍝ A two-element nested vector
 1 2 3  23
      12{⍳3}23      ⍝ A three-element nested vector
 12  1 2 3  23
      3{∘.=⍨⍳⍺⍺}    ⍝ A niladic derived function from a monadic operator
1 0 0
0 1 0
0 0 1

Multi-Line AFOHs

An AFOH may be defined on multiple lines (just like User-Defined Functions/Operators/Hyperators) by first naming it (e.g. h←{s←(+/⍵)÷2 ⋄ √×/s-0,⍵}), and then editing it in the usual way (e.g., ∇h). For more details, see Function Editing.

Guards

Guards are used to test for a condition and execute a statement or not depending upon the value of the conditional expression. This behavior is identical to the control structure

:if Cond ⋄ CondStmt ⋄ :return ⋄ :end

Guards appear as a Boolean-valued APL expression (Cond) followed by a colon, followed by a single APL statement (CondStmt) as in

{... ⋄ Cond:CondStmt ⋄ ...}

which executes CondStmt and terminates the AFOH if and only if Cond evaluates to TRUE (1).

For example,

{... ⋄ 0∊⍴⍵:'empty right argument' ⋄ ...}

As many guard statements may appear in an AFOH as desired. They are executed in turn until one of them evaluates to TRUE, at which time the statement following the colon is executed and the function terminates with any result of that conditional statement as the result of the AFOH.

If Cond does not evaluate to a Boolean-valued scalar or one-element vector, a RANK, LENGTH, or DOMAIN ERROR is signalled, as appropriate.

If the rightmost statement is executed and it is a guard statement whose Cond evaluates to FALSE (0), the AFOH terminates with no value; if the result of that AFOH is assigned, a VALUE ERROR is signalled.

Chaining Guards

If the Cond in a Guard statement evaluates to TRUE, the next statement may be another Guard statement, and so forth, each of which further reduces the likelihood of evaluating CondStmt. For example,

{Cond1: Cond2: Cond3: ... CondStmt ⋄ ...}

The effect of chaining several Guard statements together is to evaluate each Cond from Left-to-Right, and as soon as one of the Conds evaluates to FALSE, evaluation of the remainder of Conds stops and the CondStmt is skipped. Only if all Conds are TRUE is CondStmt executed.

Outside of Anonymous Functions, this syntax is equivalent to joining the Conds with :andifs as in

:if Cond1 ⋄ :andif Cond2 ⋄ :andif Cond3 ⋄ ... ⋄ CondStmt ⋄ :return ⋄ :end

Compare this with

:if Cond1 ∧ Cond2 ∧ Cond3 ... ⋄ CondStmt ⋄ :return ⋄ :end

which has the (undesired) effect evaluating all of the Conds (from Right-to-Left!) even if an early Cond evaluates to FALSE.

For example, to test for a Simple Positive Even Scalar Number,

      f←{0=≡⍵: 0 0≡⊤0,⍵: 0<⍵: 0=2|⍵: 'Oui' ⋄ 'Non'}
      f¨12 ¯12 (,12) 33 34 'A' 1r1 2r1 0r1 0v 1.1v 2v
 Oui Non Non Non Oui Non Non Oui Non Non Non Oui

Shy Results

A "shy" result is any result that doesn't automatically display its value, a simple example of which is L←⍳3: the result is ⍳3 (as evidenced by the extension to 3+L←⍳3), but because it has been assigned to a name, the result doesn't automatically display. Other ways to produce a shy result are to use the Sink syntax ←⍳3, or to call a user-defined function that declares in its header that the result is shy as in ∇ {Z}←foo R.

A shy result propagates up the chain of results just as it does through the Execute primitive. That is, if the last statement executed has a shy result, the result of Execute is shy, too.

Typically, ⎕← is used to expose a shy result.

AFOHs also may have shy results by virtue of the final result being

  • Sinked,
  • Assigned to a name, or
  • From a shy user-defined function.

For example,

      {←⍳3}
      ⎕←{←⍳3}
1 2 3
      {L←⍳3}
      ⎕←{L←⍳3}
1 2 3

Ordinarily, a shy result doesn't terminate the AFOH, as in

      {←⍳3 ⋄ 'abc'}
abc

To force termination, precede the assignment with a guard as in

{⍵=0:←'Zero' ⋄ ⍵>0:←'Positive' ⋄ ←'Negative'} R

which terminates with a shy result in all three cases.

Localization

Unlike user-defined functions, in AFOHs all names to which an assignment is made are automatically localized. As a result, a direct assignment inside an AFOH cannot affect the value of a name defined higher up in the execution chain unless it is made via a user-defined function or the Execute primitive as in

      L←⍳9 ⋄ {L←"abc" ⋄ ⍵}23
23
      L
1 2 3 4 5 6 7 8 9
      L←⍳9 ⋄ {⍎'L←"abc"' ⋄ ⍵}23
23
      L
abc

Scoping

When calls to user-defined functions are nested, a reference to a name by an inner function is resolved by looking up the chain of nested functions for the nearest level at which that name is localized. Looked at from a different perspective, when a name is localized to a function, its scope consists of all functions called by that function. This is called dynamic scoping.

AFOHs use a different mechanism where names referenced by an AFOH are resolved by the context in which the AFOH is defined, not where it is used. This is called lexical scoping or static scoping.

In other words, to paraphrase Wikipedia, "This means that if function f invokes function g that is defined outside the context of f, then under lexical scoping, function g does not have access to f's local variables (since the definition of g is not inside the definition of f), while under dynamic scoping, function g does have access to f's local variables (since the invocation of g is inside the invocation of f)".

For example,

    ∇ foo;f g a
[1]   a←'static'
[2]   ←⎕fx 'f R;a' 'a←"dynamic"' 'g R'
[3]   ←⎕fx 'g R' '"scope ←→ ",a'
[4]   f 'a'
    ∇

      foo
scope ←→ dynamic
      {a←'static' ⋄ f←{a←'dynamic' ⋄ g ⍵} ⋄ g←{'scope ←→ ',a ⋄ ⍵} ⋄ f 'a'}
scope ←→ static

Recursion

AFOHs may be called recursively, but because they might be unnamed (i.e., anonymous), the symbol is used to name the AFOH.

For example, with anonymous functions,

      ⍝ Fibonacci sequence algorithm
      f←{⍺←10 ⋄ ⍺=1:⍵ ⋄ (⍺-1)∇⍵,+/¯2↑⍵}
      f 1
1 1 2 3 5 8 13 21 34 55
      20 f 1
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
      ⍝ Euclidean algorithm for Greatest Common Divisor
      12 {⍺=0:|⍵ ⋄ (⍵|⍺)∇⍺} 8
4

With anonymous operators,

* references the operator with its operand(s) already bound (that is, references the entire derived function)
* ∇∇ references the operator with its operand(s) not bound (that is, ∇∇ references the operator itself)

That is,

* for monadic anonymous operators ∇ ←→ ⍺⍺∇∇
* for dyadic anonymous operators ∇ ←→ ⍺⍺∇∇⍵⍵

With anonymous hyperators,

* references the hyperator with both its hyperand(s) and operand(s) already bound (that is, references the entire derived function)
* ∇∇ references the hyperator with just its hyperand(s) bound (that is, ∇∇ references the operator part of the hyperator)
* ∇∇∇ references the hyperator with neither its hyperand(s) nor operand(s) bound (that is, ∇∇∇ references the hyperator itself)

That is,

* for anonymous monadic hyperand monadic operand hyperators,     ∇ ←→ ⍺⍺∇∇ ←→ ⍺⍺ ⍺⍺⍺∇∇∇
* for anonymous monadic hyperand dyadic operand hyperators,     ∇ ←→ ⍺⍺∇∇⍵⍵ ←→ ⍺⍺ ⍺⍺⍺∇∇∇⍵⍵
* for anonymous dyadic hyperand monadic operand hyperators,     ∇ ←→ ⍺⍺∇∇ ←→ ⍺⍺ ⍺⍺⍺∇∇∇⍵⍵⍵
* for anonymous dyadic hyperand dyadic operand hyperators,     ∇ ←→ ⍺⍺∇∇⍵⍵ ←→ ⍺⍺ ⍺⍺⍺∇∇∇⍵⍵⍵ ⍵⍵

For example, with anonymous operators,

      ⍝ Generalized definition of vector reduction
      f←{0=⍴⍵:⍺⍺/0⍴⍵ ⋄ 1=⍴⍵:⊂↑⍵ ⋄ ⊂(↑⍵)⍺⍺ ⊃∇1↓⍵}
      +f⍳4
10
      ×f⍳4
24
      +f(1 2)(3 4)
 4 6

A more advanced example of recursion of an anonymous operator is hyperoperation expressed below as a monadic operator where its operand N indexes successively more powerful functions as derived functions:

  • N=0 is the successor function (i.e., adds 1 to ),
  • N=1 is the addition function of to , i.e. the successor function on repeated times — ⍺+⍵,
  • N=2 is the multiplication function of by , i.e. the addition function on repeated times — +/⍵⍴a ←→ ⍺×⍵,
  • N=3 is the exponentiation function of to the power , i.e. the multiplication function on repeated times — ×/⍵⍴a ←→ ⍺*⍵,
  • N=4 is the tetration function (related to the Ackermann-Péter function), i.e. the exponentiation function on repeated times — */⍵⍴⍺,
  • N=5 is the pentation function, i.e. the tetration function on repeated times,
  • etc.

written on multiple lines using Line Continuations for clarity:

  ho←{⍺⍺=0     :⍵+1
 ⋄ (⍺⍺=1)∧⍵=0:⍺
 ⋄ (⍺⍺=2)∧⍵=0:0
 ⋄ (⍺⍺≥3)∧⍵=0:1
 ⋄ ⍺ ((⍺⍺-1)∇∇) ⍺∇⍵-1}

      2 (0 ho) 5 ⍝ Successor:  1+5 (left argument ignored)
6
      2 (1 ho) 5 ⍝ Addition:  2+5
7
      2 (2 ho) 5 ⍝ Multiplication:  2×5
10
      2 (3 ho) 5 ⍝ Exponentiation:  2*5
32
      2 (4 ho) 5 ⍝ Tetration:  */5⍴2
200352993040684646497907235156025575044782547556975141926501697371089405955...

Computing */5⍴2x takes but a fraction of a second and returns a number with 19,729 digits!

N.B.: All of the , ∇∇, and ∇∇∇ names may be used in user-defined recursive functions/operators/hyperators, where they have the same meaning as they do in AFOHs.

Termination

Normally, the statements within the braces execute one by one from left to right, just as in the Execute primitive. Execution of the AFOH terminates on the first occurrence of one of the following:

  • A Guard with a TRUE condition,
  • A non-Shy value to display, or
  • The rightmost statement.

Restrictions

  • Assignments to any of the special names (, , ⍺⍺, ∇∇, ⍵⍵, ⍺⍺⍺, ∇∇∇, ⍵⍵⍵) except for are not allowed; they signal a SYNTAX ERROR.
  • Assignments to within a guard statement are not allowed; they signal a SYNTAX ERROR.
  • None of the special names may be erased, via ⎕EX or otherwise.
  • Goto statements are not allowed; they signal a SYNTAX ERROR.
  • Control structures (e.g., :if ... ⋄ ... ⋄ :end) are not allowed; they signal a SYNTAX ERROR.
  • Line labels except for System Labels are not allowed.

Acknowledgements

This design of this feature was copied (with minor changes) from the same feature designed and implemented by John Scholes and other folks at Dyalog, Inc.