User-defined Functions and Operators
A user-defined function can be regarded as equivalent to a program in another language. Like a program, it consists of statements and has a name. When the name is typed in at the keyboard, the statements are executed.
A function can call other functions. Since several functions can exist in the workspace, this makes it possible to adopt a very modular approach to design.
The diagram below shows how a task might be split into functions. The function called
Control  Setup  Calc  Output  . Setup Calc Output [ ] Vars [ ] Sales [ ] . [ ] . [ ] . [ ] Format [ ] . [ ] Stats [ ] Window [ ] . [ ] . Vars Window Sales Stats Format [ ] . [ ] . [ ] . [ ] . [ ] .
Any of the functions could of course be used with other functions to do a different overall task.
Functions are often only a few lines long, so the structure shown doesn't necessarily represent some vast commercial project. With APL a modular approach comes naturally even for smallish programming tasks.
Arguments and results
User functions need not have arguments. A user function may be a series of APL lines with a name which, when entered, causes the lines to be executed. The name on its own calls the function and no arguments are specified. Such functions are called niladic functions.
Alternatively, functions can be defined in such a way that when you call them, you must provide arguments, just as you would with a built-in APL function. Here for example, the built-in function
⌈6.5009 12.7 33.33333 909.01
The numbers are supplied as the right-hand argument.
If you defined a function called, say,
SD 23 89 56 12 99 2 16 92
Functions with one argument, like
You specify the number of arguments the function is to have, and the name of the result field (if there is one) when you define the function header of the function you are about to write.
User-defined operators are rather more complex, in that they will have one or two operands, that is functions that they will apply to data and the function that results from the combination of operator and operands may itself have one or two arguments. Since operators exist to modify the behaviour of functions, a user-defined operator must have at least one operand.
User-defined operators can be treated like user-defined functions for the purposes of editing and entry.
In most versions of APLX, there are two ways to create or edit a function.
The most commonly used way is to use a full-screen editor, which allows you to edit the function text very easily in an editor window. The editor is either invoked through the application's Edit menu, or with the
Here is a snapshot of an editor window on a Windows system, showing a function called
For backward compatibility with old APL systems, APLX also supports a primitive line-at-a-time editor called the Del editor. To enter definition mode and create a new function you type
For clarity, we will list functions here as though they were entered using the Del editor, where a
If you are using the normal full-screen editor, you do not type the
The function header
The first line of a function is called the function header. This example is the header for a function called
If you want the function you are defining to have arguments you must put them in the header by typing a suitable function header:
The above header specifies that
∇SD X  SUM ← +/X  AV ← SUM÷⍴X  DIFF ← AV-X  SQDIFF ← DIFF*2  SQAV ← (+/SQDIFF)÷⍴SQDIFF  RESULT ← SQAV*0.5 ∇
It's quite unimportant what the statements in the function are doing. The point to notice is that they use the variable
SD 12 45 20 68 92 108
those numbers are put in
The function header for a dyadic (two-argument) function would be defined on the same lines:
∇X CALC Y
(Remember that you don't type the
When you subsequently use
1 4 7 CALC 0 92 3
If you want the result of a function to be put into a specified variable, you can arrange that in the function header too:
∇Z ← X CALC Y
In practice most APL functions return a result, which can then be used in expressions for further calculations, or stored in variables.
The operator header
The operator header must accommodate operands as well as the arguments of the function derived from it and so the header is more complex. The operator name and its operands are enclosed in parentheses. Thus a monadic operator whose derived functions will take two arguments and return a result, has a header:
∇R ← X (LOP OPERATE) Y
∇R ← X (LOP OPERATE ROP) Y
Other than its special header line, user-defined operators obey the same internal rules as detailed below for user-defined functions.
Local and global variables
Variable names quoted in the header of a function are local. They exist only while the function is running and it doesn't matter if they duplicate the names of other variables in the workspace.
The other variables - those used in the body of a function but not quoted in the header, or those created in calculator mode - are called global variables.
It's obviously convenient to use local variables in a function. It means that if you decide to make use of a function written some time before, you don't have to worry about the variable names it uses duplicating names already in the workspace.
But to go back to the
You can 'localise' any variable used in a function by putting a semicolon at the end of the function header and typing the variable name after it:
You may wonder what happens if functions that call each other use duplicate local variable names. You can think of the functions as forming a stack with the one currently running at the top, the one that called it next down, and so on. A reference to a local variable name applies to the variable used by the function currently at the top of the stack.
Traditionally, the APL right arrow '
We'll start by introducing the traditional APL branching technique, which is supported by all APL dialects, before considering the modern APLX alternative of using structured-control keywords like
You will rarely use
 ...  →4  ...  ...
When this function is run, line 1 is obeyed, then line 2 then line 4. Line 3 is always omitted because the
 ...  ...  ...  → 1
It's more common to use
 →(MARK<PASS)/7  'YOU PASSED. CONGRATULATIONS.'  ...  ...  'BAD LUCK. TRY AGAIN.'
The statement on line
 goto 7 if MARK<PASS
There are very many different ways of generating branches within an APL function, and these are discussed in more detail in the APLX Language Manual. For now, the expression used in the example above will be used to generate branches in a function.
The last example provides a situation where an unconditional branch may be appropriate. If
 →(MARK<PASS)/7  'YOU PASSED. CONGRATULATIONS.'  ...  →9  'BAD LUCK. TRY AGAIN.'  ...  ...
Branching in many programming languages is used to set up loops: sequences of instructions that are obeyed repeatedly till a count reaches a certain value. The count, of course, is incremented each time the loop is executed.
Loops are rarely necessary in APL, since much of the counting that has to be specified in other languages is implicit in the data structures used in APL and is done automatically, For example, the following statement will add the values in
If a loop is necessary, it can be constructed using a statement similar to the branch statement shown above, the condition test being the value of a loop count. (The entry for
After an editing session in which you've inserted or deleted lines, the function editor renumbers the function to make sure lines are whole numbers and there are no gaps. So next time you edit or run the function, the line numbers may be different. For this reason it's much safer to 'goto' labels rather than to line numbers.
Here's an earlier example, this time with
 →(MARK<PASS)/FAIL  'YOU PASSED. CONGRATULATIONS.'  ...  →NEXT  FAIL: 'BAD LUCK. TRY AGAIN.'  ...  NEXT: ...
Labels are names followed by colons, They are treated as local variables and have the value of the line numbers with which they are associated. For example, the label
Ending execution of a function
When the last line in a function is executed, the function stops naturally (unless, of course, the last line is a branch back to an earlier line). To end a function before the last line is encountered, you can go to a line number which doesn't exist in the function. The safest line number for this purpose (and the one conventionally used) is 0.
The following statement causes a branch to 0 (in other words, terminates the function) if a variable called
Structured control keywords
As well as the conventional branch arrow, APLX supports structured-control keywords for flow control, often making for more readable functions. The keywords all begin with a colon character, and usually appear at the start of the line (APLX will automatically indent lines within a block for you). For example:
 :If MARK ≥ PASS  'YOU PASSED. CONGRATULATIONS.'  ...  :Else  'BAD LUCK. TRY AGAIN.'  ...  :Endif
The structured control keywords are not part of the International Standards Organisation (ISO) specification of the APL language, but they are supported by a number of APL implementations including APLX.
Structured control keywords include:
Here is a simple example:
∇GUESS;VAL  'Guess a number'  :Repeat  VAL ← ⎕  :If VAL=231153  'You were right!'  :Leave  :EndIf  'Sorry, try again..'  :EndRepeat ∇
The amount of indentation does not affect the execution of the function, but it does make it easier to read. If you are using the editor window, you can select 'Clean up indentation' from the Edit menu to ident the function appropriately.
See 'Control Structures' in the APLX Language Manual for further details.
Comments in functions
If you want to include comments in a function, simply type them in, preceded by a
∇R ← AV X  ⍝ This function finds the average of some numbers  R ← (+/X)÷⍴X ⍝ The numbers are in X
There are two comments in the example above. Note that the one on line 2 doesn't start at the beginning of a line.
It's possible to lock a function. A locked function can only be run. You can't edit it or list the statements it consists of. To lock a function, edit it in the Del editor but type a
There may be occasions when you want to make code secure from tampering or scrutiny. But be certain that it's error-free and in its final form - a locked function cannot be unlocked.
All dyadic functions may be used monadically. If used monadically, the left argument is undefined (i.e. has a Name Classification,
∇R←A NOMADIC B  :If 0=⎕NC 'A' ⍝ DOES A EXIST?  A←5 ⍝ NO, SO WE HAVE BEEN USED MONADICALLY  :EndIf ...etc ∇
Copyright © 1996-2008 MicroAPL Ltd