A+ Reference: Defined Functions and Operators

# Defined Functions and Operators

Scope of Names
Function Syntax
Operator Syntax
Entry of Programs
Formatting a Defined Function or Operator

> Programs (user-defined functions and operators) are defined when they are entered in an A+ session. They may be entered at the keyboard, effected when a character vector containing a definition is executed, brought in from a script during the execution of a $load command, or, in an Emacs A+ session, brought in from any Emacs buffer, including the A+ one. In any case, the same rules apply regarding the form in which programs must be entered.

> In Emacs, to bring in a program all at once, place the cursor anywhere in it and press the F3 key. To bring it in a line at a time, or just to retrieve individual lines, place the cursor on each line successively and press the F2 key. After either of these keys has been pressed, if the source buffer is not the A+ buffer, there will be two buffers in the window, A+ and source. Caution: The F3 key causes the program to be read exactly as it appears in the file, so if there are asterisks indicating continuation of the definition (as in a multiline definition entered in an A+ session), these asterisks will either cause a parse error or result in a presumably unexpected new definition.

> (Cf. "The Syntax and Semantics of A+" and "Workspaces and Scripts".)

> A program consists of a header and a body separated by a colon (:). The header consists of the name of the program along with its argument names. The body is an expression or expression group. The result of a program is the result of the expression group that forms the body. See "Function Definitions" and "Operator Definitions" for detailed descriptions of headers and bodies. A simple example of a function definition is

>          r f p:¢1+(1+rßp)*p    ã Simple to compound interest, with p periods.

# Scope of Names

> The value of a local variable in a program (defined function or operator) is strictly local: it can be seen only within that program, and not by calling programs or called programs. This rule for local variables is sometimes called static scoping, or lexical scoping. (Note, however, that if the local variable is a mapped file, the file value can be seen elsewhere; see "Mapped Files".)

> The arguments to a program are local to that program.

> The name of the program is global, and furthermore the unqualified form of that name is also considered global within the program, and therefore any occurrence of it refers to the program.

> Fully qualified names within the program - ones that explicitly refer to contexts, like ctx.var and .fn - are always global, and so are the names (in symbol form) appearing in Value and Value in Context expressions. If possible, these are the preferred ways to indicate that a name is global.

> Names in arguments for Execute are not seen during parsing of the program and play no role in determining whether unqualified names are local or global.

> Any unqualified name not covered above is local if, anywhere in the program, it is the target, without extra parentheses, of an ordinary or Strand Assignment, for example aûb+c or (a;b)û(c;d).

> Otherwise any such name is global: either it is only referenced, not specified, in the program, or wherever it appears as a target it is parenthesized, for example (a)ûb+c or ((a);(b))û(c;d). Because of the way this aspect of Strand Assignment is implemented, at least currently such an assignment does not make a name local if there is more than one right parenthesis between the name and the left arrow; thus the assignments ((a;b))û(x;y) and (c;(d);e)û(x;y;z) force only e to be local.

> The context for a visible unqualified global name is the context of the program, i.e., the context explicitly given in the program name in the header, or, if that name is unqualified, the current context when the program was defined. A statement that may later be executed as a Context command, â"$cx ...", does not change the context during program definition. See "Assignment" and "Contexts". Within a program, the program's context can be obtained by 0#Ö_name<{%}.

> A character string or substring or symbol that may later be interpreted as an unqualified global name, using Execute or Value, is not a visible unqualified global name (when the program is defined). The context that is used for such text is determined only when it emerges as a name, i.e., when it is executed, and it will be whatever context is current at that time. That current context could be the context when the program was invoked or one established by the execution of a Context command within the program or a program called by it.

# Function Syntax

> A function is a program that takes from zero to nine data arguments and returns a result. Examples of functions that take 0 (niladic), 1 (monadic), 2 (dyadic), and 3 arguments are shown in Table 4.3, "Function Call Expressions and Function Header Formats". (Although a dependency is a kind of niladic defined function, it is different enough in form and operation that it is treated separately, in "Dependencies", and ignored here.) For monadic and dyadic functions, for both definition and use, the two possible forms are shown: infix and general. No matter which form is used when the function is defined, either form can appear when it is used.

# Operator Syntax

> An operator definition is a program that takes
> 1. one function operand, two function operands, or a function operand and a data operand, and

> 2. one or two data arguments,
> and returns a result. It is distinguished from a function definition by parentheses in the header that surround the expression consisting of the operator name and its operands. Examples of the possible headers are shown in "Operator Header Formats".

> In each form in that table, the left operand, f, must be a function. When is the right operand, h, a data variable and when is it a function? If in the operator definition it has the name g, it is a function. If it has any name there other than g, it is a data variable unless in every occurrence of it in the body of the definition it can only be a function. Examples of such occurrences are ... h¡ ... and ... h{...} ... .

> To repeat: the left operand is always a function. If the right operand is not named g in the definition, it is a data variable if there is an occurrence of it in the body of the definition where it either must (e.g., ... h[...] ...) or could possibly (e.g., ... hß2 3 4 ... or ... h/...) be a data variable. Otherwise the right operand is a function.

> Operators have higher priority than functions. The arguments defined within the parentheses are bound to the operators before the derived function is applied to its data arguments.

> Operators have long left scope and short right scope. This is the mirror image of functions, which have long right scope and short left scope. For example, the expression 100 200 ,@1@¢1 É2 3 4 is the same as the expression with redundant parentheses 100 200((,@1)@¢1)É2 3 4.

# Entry of Programs

> Single-statement programs are normally entered on a single line, as in

>     mean x: (+/x)ß#x

> Multiple-statement programs may be entered on one or more lines. The definition is not complete until any open quotation mark and all open braces and parentheses are closed. Be sure to see "Workspaces and Scripts" regarding continuation rules during entry of statements and functions, and asterisks that A+ supplies to indicate depth of punctuation. These asterisks are not shown in this chapter.

> Here is a sample multistatement multiline function definition:

>     total m : {
>        ã Append row, column, grand totals to matrix.
>        cû+/m;          ã Column totals.
>        rû+/ôm;         ã Row totals.
>        (ô(ôm),r),c,+/c
>        }

> This function could be defined more efficiently using the Rank operator rather than Transpose:

>     total m:{
>        ã Append row, column, grand totals to matrix.
>        cû+/m;  rû+/@1 m;    ã Column and row totals.
>        (m ,@1 0 r),c,+/c
>        }

> Notice that the comments are comments to lines, not to statements. They do not appear before the statement semicolons and they do not have their own semicolons. Even if there are several statements on a line, there can still be only one comment.

> Defined functions can of course appear in the definitions of defined functions, as in

>          y f x:0Óg{y}ßg{x}

> Notice that g appears in general form, not in infix form. Although either form is valid, it is a good practice, especially in scripts, to use the always unambiguous general form within the body of a definition. Then it doesn't matter whether g is defined before or after f; when it appears in the definition of f A+ will surely be able to determine that it is a function and not a variable.

> Here is a sample operator definition, showing how the right operand can be a data value:

>     u(f p a)v:{
>          case(a){
>                    1 ; u f  (Òu)Ùv;
>                    ¢1; u f (-Òu)Ùv;
>                    0 ; u f     0#v;
>                    Ù'Incorrect right operand'}
>          }

> In the following operator definition, both operands must be functions, as shown by the syntax. Defined operators can be used in the definitions of defined operators, like inv in this example:

>          y (f iso g) x:(g inv){f{g{y};g{x}}}

Indentation, Blanks and Tabs

> When the name of a program is entered alone on a line, without arguments or braces, A+ displays the program definition. It is shown just as it was entered, with the spacing preserved, with two exceptions:
> 1. Any invisible characters (blanks, tabs, ...) before the first visible character in the function are eliminated. If you want to see on entry what will be displayed later, start the header at the left margin, eliminating the blanks supplied at the beginning of each input line in an A+ session.

> 2. If the function was entered in an A+ session (rather than in a script or other file), the spacing within each line is preserved but the indentation is generally not: the first nonblank character of each line after the first is shown at the left margin. In these lines, it is specifically the blank character that is dropped, however; other invisible characters are kept. You can force the original indentation to be honored in successor lines by using tabs. All tabs and any blanks that follow a tab are kept.
> Thus, if in an Emacs A+ session you enter

>          f1{x;y}:{
>                  if (x=0) {
>                         ...;
>                         ...};
>                     else  {
>                         ...}
>                  }

> using just blanks to obtain the indentation, you get this display

>          f1
>     f1{x;y}:{
>     if (x=0) {
>     ...;
>     ...};
>     else  {
>     ...}
>     }

> whereas if you enter

>     f1{x;y}:{
>            if (x=0) {
>               ...;
>               ...};
>               else  {
>               ...}
>           }

> using tabs, at least as the first character on each successor line, you get a display exactly matching your input.

## Formatting a Defined Function or Operator

> At times it may be convenient to convert a defined function or operator to text. Examples of the need for this would include printing formatted reports of code from the workspace or dynamic inspection of the code. However, it may not be obvious just how to format these objects into text. It is done like this:

>          avg
>     avg v : {(+/v)ß#v}

>          matûî<{avg}     ã here is the technique

>          mat
>     avg v : {(+/v)ß#v}

>          Òmat
>      18

> This is the format (î) of a function scalar.