Anonymous Functions/Operators/Hyperators: Difference between revisions

From NARS2000
Jump to navigationJump to search
No edit summary
No edit summary
Line 1: Line 1:
Anonymous functions and operators 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 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>.


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


Normally, the statements within the braces execute one by one from left to right, just as in execute.  Execution of the anonymous function/operator terminates on the first occurrence of one of the following:
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:


* a [[#Guards|Guard]] with a TRUE condition,
* A [[#Guards|Guard]] with a TRUE condition,
* a non-[[#Shy Results|Shy]] value, or
* A non-[[#Shy Results|Shy]] value, or
* the rightmost statement.
* The rightmost statement.




Line 66: Line 66:
</table>
</table>


<h3>Ambivalent Anonymous Functions/Operators</h3>
<h3>Ambivalent AFOs</h3>


User-defined functions allow you to specify in their headers that the left argument is optional as in <apll>∇ Z←{L} foo R</apll>.  This behavior is also available to anonymous functions/operators 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 using <apll>0=⎕NC '⍺'</apll> to test for a value in <apll>⍺</apll>.
User-defined functions allow you to specify in their headers that the left argument is optional 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 using <apll>0=⎕NC '⍺'</apll> to test for a value in <apll>⍺</apll>.


For example,
For example,
Line 89: Line 89:
1 2 3 3</apll>
1 2 3 3</apll>


As a consequence of this rule, regardless of whether the anonymous function is called monadically or dyadically, any second or subsequent statements that assign a value to <apll>⍺</apll> are always ignored.
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.


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


An anonymous function/operator may be
An AFO may be


* ambivalent (may be called with one or two arguments),
* Ambivalent (must be called with either one or two arguments),
* dyadic (must be called with two arguments),
* Dyadic (must be called with two arguments),
* monadic (must be called with one argument only), or
* Monadic (must be called with one argument only), or
* niladic (must be called with no arguments),
* Niladic (must be called with no arguments),


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


*For anonymous functions (and operators):
*For anonymous functions (and operators):
** if <apll>⍺←</apll> appears as a sequence of tokens, then the object is an ambivalent (derived) function,
** 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 dyadic (derived) function,
** otherwise, if <apll>⍵</apll> appears as a token, the object is a monadic (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.
** Otherwise, if neither <apll>⍺</apll> nor <apll>⍵</apll> appears as a token, the object is a niladic (derived) function.
*For anonymous operators:
*For anonymous operators:
** if <apll>⍵⍵</apll> appears as a token, the operator is dyadic (requires two operands),
** If <apll>⍵⍵</apll> appears as a token, the operator is dyadic (requires two operands),
** otherwise, it is monadic (requires a left operand only).
** Otherwise, it is monadic (requires a left operand only).


For the moment the case of a niladic derived function from either a monadic or dyadic operator signals a <apll>NONCE ERROR</apll>.
For the moment the case of a niladic derived function from either a monadic or dyadic operator signals a <apll>NONCE ERROR</apll>.
Line 150: Line 150:
<apll>{... ⋄ Cond:CondStmt ⋄ ....}</apll>
<apll>{... ⋄ Cond:CondStmt ⋄ ....}</apll>


which executes <apll>CondStmt</apll> and terminates the anonymous function/operator iff and only if <apll>Cond</apll> is TRUE.
which executes <apll>CondStmt</apll> and terminates the AFO if and only if <apll>Cond</apll> evaluates to TRUE (<apll>1</apll>).


For example,
For example,
Line 156: Line 156:
<apll>{... ⋄ 0∊⍴⍵:'empty right argument' ⋄ ....}</apll>
<apll>{... ⋄ 0∊⍴⍵:'empty right argument' ⋄ ....}</apll>


As many guard statements may appear in an anonymous function/operator as desired.  They are evaluated in turn until one of them is 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 anonymous function/operator.
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.


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.
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.
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.


<h3>Shy Results</h3>
<h3>Shy Results</h3>
Line 168: Line 170:
Typically, <apll>⎕←</apll> is used to expose a shy result.
Typically, <apll>⎕←</apll> is used to expose a shy result.


Anonymous functions/operators also may have shy results by virtue of the final result being
AFOs 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 182: Line 184:
1 2 3</apll>
1 2 3</apll>


Ordinarily, a shy result doesn't terminate the anonymous function/operator, as in
Ordinarily, a shy result doesn't terminate the AFO, as in


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{←⍳3 ⋄ 'abc'}<br />
<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{←⍳3 ⋄ 'abc'}<br />
Line 195: Line 197:
<h3>Localization</h3>
<h3>Localization</h3>


Unlike user-defined functions, in anonymous functions/operators all variables to which an assignment is made are automatically localized.  As a result, a direct assignment inside an anonymous function/operator cannot affect the value of a variable 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 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


<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L←⍳9 ⋄ {L←"abc" ⋄ ⍵}23<br />
<apll>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L←⍳9 ⋄ {L←"abc" ⋄ ⍵}23<br />
Line 220: Line 222:
<h3>Restrictions</h3>
<h3>Restrictions</h3>


* For the moment, anonymous functions/operators may be written on one line only.
* For the moment, AFOs may be written on one line only.
* As a consequence of the above one-line restriction, anonymous functions/operators may not contain comments.
* As a consequence of the above one-line restriction, AFOs may not contain comments.
* Anonymous functions/operators may not assign anything to any of the special names (<apll>∇</apll>, <apll>⍵</apll>, <apll>⍺⍺</apll>, <apll>∇∇</apll>, <apll>⍵⍵</apll>) except for <apll>⍺</apll>. Any attempt to do so signals a <apll>SYNTAX ERROR</apll>.
* 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 <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 in anonymous functions/operators; they signal a <apll>SYNTAX ERROR</apll>.
* Goto statements (including <apll>→</apll>, <apll>→0</apll>, and <apll>→⍬</apll>) are not allowed; they signal a <apll>SYNTAX ERROR</apll>.
* Control structures such as <apll>:if ... ⋄ ... ⋄ :end</apll> are not allowed in anonymous functions/operators; 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>.

Revision as of 16:30, 14 July 2013

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

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

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:

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


Function Arguments

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

      3{√+/⍺ ⍵*2}4                ⍝ Pythagorean theorem
5
      {s←(+/⍵)÷2 ⋄ √×/s-0,⍵}3 4 5 ⍝ Heron's formula for triangle area
6

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 operator (for recursion), and ⍵⍵ as the name of the right operand. If neither ⍺⍺ nor ⍵⍵ appears as a token (outside of character constants) between the braces, then the object is a function, not an operator. For example,

f←{∘.⍺⍺⍨⍳⍵}

   =f 4
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

   ⌈f 4
1 2 3 4
2 2 3 4
3 3 3 4
4 4 4 4

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

   ≤f 4
1 1 1 1
0 1 1 1
0 0 1 1
0 0 0 1

Ambivalent AFOs

User-defined functions allow you to specify in their headers that the left argument is optional as in ∇ Z←{L} foo R. This behavior is also available to AFOs 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 using 0=⎕NC '⍺' to test for a value in .

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

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 are always ignored.

Valences

An AFO 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 only), 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

  • For anonymous functions (and operators):
    • If ⍺← appears as a sequence of tokens, then the object is an ambivalent (derived) function,
    • Otherwise, if appears as a token, the object is a dyadic (derived) function,
    • Otherwise, if appears as a token, the object is a monadic (derived) function,
    • Otherwise, if neither nor appears as a token, the object is a niladic (derived) function.
  • For anonymous operators:
    • If ⍵⍵ appears as a token, the operator is dyadic (requires two operands),
    • Otherwise, it is monadic (requires a left operand only).

For the moment the case of a niladic derived function from either a monadic or dyadic operator signals a NONCE ERROR.

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

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 AFO if and only if Cond evaluates to TRUE (1).

For example,

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

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.

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

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

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 is inherited up the chain of results such as 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.

AFOs 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 AFO, 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 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

      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

TBD


Recursion

TBD


Restrictions

  • For the moment, AFOs may be written on one line only.
  • As a consequence of the above one-line restriction, AFOs may not contain comments.
  • 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 (including , →0, and →⍬) are not allowed; they signal a SYNTAX ERROR.
  • Control structures such as :if ... ⋄ ... ⋄ :end are not allowed; they signal a SYNTAX ERROR.