Writing a Function (6 of 14)
Precondition: the Slash operator
You may already have looked this up in your APL manual as suggested at the end of session 1. But since it's used in one of the functions you're going to write, we'll cover it briefly just in case. / is called Slash or Reduce.
Note that in the context in which we're describing it here, / is an operator not a function; it modifies or extends the operation of the functions it's used with. Here's an example of its use:
+/ 1 6 3 4 14
What / did was to extend the operation of + so that the expression effectively became:
Here's an example using multiply:
×/ 1 2 3 4 24
Multiply was used on each number in the list like this:
Let's see how this works on a table:
TABLE ← 3 3 ⍴⍳9 TABLE 1 2 3 4 5 6 7 8 9 +/ TABLE 6 15 24
It won't take you a moment to work out what APL has done to produce the three numbers 6 15 24.
Obviously they're the sum of the numbers in each row. (If you want to make the +/ operation apply to columns instead of rows, this is easily done. Try looking up , Axes, in your APL manual.)
Remembering APL's rule of working from right to left, and the fact that one function's results are data to the next function down the line, enter an expression that will sum all the numbers in the table.
This is one solution:
+/ +/ TABLE 45
We know that the result of the first (ie the right-hand) part of the statement is 6 15 24. So these three numbers are the data for the left-hand +/. Their sum is 45.
You can add the numbers in just one column by the usual method of indexing. Here's TABLE again followed by a statement which adds the numbers in the first column:
TABLE 1 2 3 4 5 6 7 8 9 +/ TABLE [;1] 12
Here's a useful combination: the function ⌈ used with / selects the largest number from a list:
⌈/75 72 78 90 69 77 81 88 90
While the equivalent ⌊ statement naturally produces the smallest number:
⌊/ 75 72 78 90 69 77 81 88 69
In case it crossed your mind that ⌈ and ⌊ were being used in their one-argument forms in the last two examples, remember that what / does is to put the function (⌈,⌊ or whatever) between each element of the data it's applied to like this:
75 ⌈ 72 ⌈ 78 ⌈ 90 ⌈ 69 ⌈ 77 ⌈ 81 ⌈ 88
Here's a final example of the use of / for you to ponder before you go on to the topic of function definition. What does this example do?
X ← 1 2 3 4 5 (+/X)÷⍴X 3
Hitherto your APL statements have worked their way up the screen and, when they reached the top, have disappeared without trace. You're about to learn how to preserve statements, or groups of statements, so that you can summon them back for execution or amendment at any time. In other words you're going to find out how to write a function. A user-defined function in APL is like a program in another language. It has a name and consists of APL statements. When you quote the name, the statements are executed consecutively, or in whatever order you specified when you defined the function.
Writing a Function
Most versions of APL include a full-screen editor, which allows you to edit the function text very easily in an editor window. The method of invoking the editor will vary from one vendor's APL to another; try looking at application's menu bar, or try the )EDIT system command e.g.
Note: Some APLs like Dyalog use )ED to invoke the editor, e.g. )ED FUNK
Older APL systems used a primitive line-at-a-time editor called the Del editor, and it's still supported by some versions of APL. To enter definition mode and create a new function you type ∇ (Del) followed by the function name. If you type nothing else, you are defining a function that will take no arguments:
You will probably never need to learn the Del editor. If you do accidentally type a ∇ character to enter definition mode, just type another ∇ to get back to calculator mode.
There is one exception, so: NARS2000 does not have a del editor, so it interprets the ∇ character as a shortcut for )edit.
For clarity, we will list functions here as though they were entered using the Del editor, where a ∇ character is used to mark the start and end of the function listing. Listing functions in this way makes it clear at a glance that you are looking at a function. It's also a convention commonly used in other APL documentation on the Internet.
If you are using the normal full-screen editor, you do not type the ∇ characters or the line numbers.
APL requires to know the name of the function you're defining. Your first function will be called TRY1 so enter:
Enter the following function (Remember that you don't type the ∇ or the line numbers):
∇TRY1  'Type some numbers: '  NUM ← ⎕  'Total is: '(+/NUM) ∇
(The ⎕ symbol is called Quad and is found on the 'L' on the keyboard. What the ⎕ does will be quite clear in a couple of minutes)
To save the function, select the appropriate menu item from the editor window's menu bar (APLs will vary) and then close the window.
Running a Function
Now you're ready to run the function you've written. Type the function name to run it:
TRY1 Type some numbers: ⎕:
Type in a few numbers as the message suggests:
93 7 0 2 Total is: 102
If you get errors while running a function just use )EDIT TRY1 to get back to the edit window, where you can correct your mistake. Alternatively if you're ready to explore further, you could investigate whether your APL has a Debug window.
Now you've seen what the function does, we'll go very briefly through the APL statements that make it up.
- Line 1 was entered as:
'Type some numbers: '
It behaves exactly as you'd expect. When the function is executed, the text in quotes is displayed on the screen.
- Line 2 consisted of:
NUM ← ⎕
Quad (⎕), as used here, tells APL to wait for something to be typed in on the keyboard. So this line means 'Accept some input from the keyboard, then assign that input to the variable NUM'. Line 2 was responsible for the invitation to type (ie the Quad symbol and colon) which appeared after the line of text when the function was executed.
- Line 3 was as follows:
'Total is: '(+/NUM)
Working from the right, it first adds the numbers in NUM,that is, the numbers which were typed in, then it displays the result preceded by the text "Total is: ". We have made up a nested list (remember the rules about parentheses).
Editing a function
Now suppose you want to add a line to this function, telling the user how many numbers he or she typed in. To modify the function, just open a new edit window:
You want to insert a step to display a message saying how many numbers were entered. This step should go between the present lines 2 and 3:
'You have entered' (⍴NUM) 'numbers'
Run your amended function and check that it works:
TRY1 Type some numbers: ⎕: 93 7 0 2 You have entered 4 numbers Total is: 102
How about inserting yet another step? You no doubt recognised that the statement you were left to ponder earlier in this chapter worked out the average of a group of numbers.
Why not insert a step at the end of TRY1 which displays the average of the numbers in NUM? Rejoin the Wiki when you've done that.
Line 5 of TRY1 should now look like this, though your text in quotes may be different:
'Average is:' ((+/NUM)÷⍴NUM)
See if it runs then read on regardless of the result!
Now make use of the function editor to add a couple of lines to TRY1. You want the function to print out the biggest and smallest of the numbers entered, together with some suitable text.
Hopefully all went well, and you ended up with a function looking something like this:
∇TRY1  'Type some numbers: '  NUM ← ⎕  'You have entered' (⍴NUM) 'numbers'  'The biggest was: ' (⌈/NUM)  'The smallest was: ' (⌊/NUM)  'Total is: '(+/NUM)  'Average is:' ((+/NUM)÷⍴NUM) ∇
Saving a workspace
So far you have saved the function TRY1 in the workspace, but the workspace itself has not been saved to disk. If you were to end your APL session now all your work would be lost.
You may have doubts about saving the workspace containing TRY1. But do it anyway as a dry run for when you have something you really want to save.
First check what variables you have in your workspace:
)VARS NUM TABLE X (your list may be different.)
There's a system command for enquiring about functions which you can now use:
You're going to save the workspace, so you may as well first erase TABLE, X and any other variables you have in your workspace which aren't needed by TRY1:
)ERASE TABLE X
)ERASE is another system command. It lets you erase one or several variables or functions from the workspace in memory. You can check that the erasures took place by issuing another )VARS if you want.
The next step is to save your workspace. One way to do this in most APL interpreters is to use the "Save" option (or similar) in the menu bar, but it's also useful to be familiar with the )SAVE command which all APLs implement...
In order to use )SAVE you have to specify a name for your workspace. This is done with the system command )WSID (WorkSpace ID):
The new name of your workspace is shown in the caption of the session window.
Instead of providing only the workspace name as such you can also provide a full path. For example, under Windows you might type:
Without a path, most APLs save the workspace in the current directory; Only NARS2000 will save the workspace in a Windows standard folder for application data. This is, if you are working as user "foo", something like:
C:\Documents and Settings\foo\Application Data\NARS2000\workspaces\
To actually save the workspace:
Now you know that workspace is saved on disc, you can clear the workspace in memory using the familiar command:
)CLEAR CLEAR WS
You can check that it's worked by typing:
The function TRY1 is no longer there.
You can get the workspace back into memory by selecting the Open/load workspace item in the menu bar (Exact details are vendor-dependent), or by using the )LOAD command:
The workspace you select will be read into memory. Check that TRY1 is back by issuing a )FNS command.
User functions with arguments
If you compare TRY1 with the functions built-in to APL, one point should strike you: TRY1 has no arguments.
User functions can, in fact, have no arguments, one argument or two arguments.
Let's take the expression used in TRY1 to find the average of the numbers and define it as a one-argument function called AV. The intention is that once AV exists, we should be able to use it like a built-in APL function. We should, for example, be able to type:
AV 12 7 3 1
and get a result which is the average of the numbers on the right.
Here's the first line of AV, known as the function header statement. When defining the function header, we have to indicate that the function will take an argument to its right:
We've used X to represent the right-hand argument, that is, the data AV will work on.
Here's the complete function:
∇AV X  (+/X)÷⍴X
We've assumed the numbers to be averaged are in the variable called X. That's all there is to AV, so create the function using )EDIT AV and try it out:
AV 3 8 1 4 4 AV 192 4534 12 0 2 948
It will work equally well if the right-hand argument is a variable:
NUM ← 1 2 3 4 5 AV NUM 3
As you can see, any value to the right of AV, whether a directly-quoted number, or a value in a variable, is substituted for the X we used in the function definition.
User functions with two arguments work very similarly. In the function header, the arguments are represented by variable names on either side of the function name. For example, for a function called MPH intended to work on two arguments, namely distance and time, the header might be:
∇D MPH T
The function AV printed its result directly to the screen. If you want the function to return a result which can be used in further APL expressions, you need to change AV as follows:
∇R←AV X  R←(+/X)÷⍴X
Here, the average is assigned to a result R, allowing you to do things like:
¯3 + AV 3 8 1 4 1
But you'll have to find out about this, and other types of user-defined functions, on your own. We will return to the subject in a later chapter.
Functions within functions
There's no reason why AV should not be used in TRY1 to work out the average of the numbers input and held in NUM
Try editing TRY1, then check that the new arrangement works.