9. Special Syntax¶
9.1. Modified Assignment¶
Changes to a variable, like
a ← 4
languages ← 'APLL' 'Pithon' 'Jaba'
frequently involve modifying its current value, and such expressions naturally contain two references to its name:
⎕← a ← a + 1
⎕← languages ← languages,'Cee' 'Paskal' 'Russt'
⎕← languageThousandsUsersByYear ← 4 6⍴2562 2435 3254 9843 6234 2634 2345 6543 9875 2452 5645 2345 3411 5462 8787 2435 2435 7634 5632 6543 2345 2345 6486 3452
If the variable has a long name, its repetetition causes the expression to be rather lengthy too.
If you want to change just part of the variable using indexing, there is even more repetition:
⎕← languageThousandsUsersByYear[2 3;1 4 5 6] ← languageThousandsUsersByYear[2 3;1 4 5 6] - 100
Dyalog APL has a feature that allows you to avoid this type of repetition; it is called modified assignment.
In an expression that uses modified assignment, the name of the variable to be modified appears just once, at the beginning of the expression. This is followed by the function to be used to change its value, then the assignment arrow, and then the array that specifies the amount by which the original value of the variable is to be changed. This array would otherwise appear as the right argument of the function:
a ← a + 1, one can write
a +← 1
And instead of
languages ← languages,'Cee' 'Paskal' 'Russt' one can write
languages ,← 'Cee' 'Paskal' 'Russt'
Using modified assignment, the other expression can be rewritten as follows:
languageThousandsUsersByYear[2 3;1 4 5 6] -← 100
Modified assignment is concise and can reduce errors (such as misspelling the variable name in the second part of the expression).
However, there is a disadvantage to modified assignment: when reading a statement it is very easy to miss the function to the left of the assignment arrow and assume that the statement contains a plain assignment.
Modified assignment can be used to enter a very long list of values, which would otherwise exceed the screen width, as illustrated in the following example:
vec ← 52 17 39 77 40 17 29 0 0 14 vec ,← 80 12 31 46 100 51 49 43 21 vec ,← 17 18 19 63 61 70 44 0 20 11 vec
This type of modified assignment might be superseded by the introduction of an array notation which would make it more convenient to write out explicit arrays.
9.2. Multiple Assignment¶
It is possible to assign several values to several variables at the same time. This is as true for nested arrays as it is for simple arrays:
(a b c) ← 23 41 56
(d e f) ← (20 61) (2 2⍴⍳4) 'Africa'
These two instructions are equivalent to the individual assignments
a ← 23,
b ← 41, …
f are vectors, and
e is a matrix: they are not nested.
This technique, called multiple assignment, is a simple way to split the contents of a simple or nested vector into several variables.
This technique can be combined with the modified assignment seen previously.
For example, we can update
c (which we have just set to
56, respectively), as follows:
(a b c) +← 57 (19 ¯16) (2 3⍴⍳6)
a b c
Of course, the number of variable names must be equal to the length of the vector to the right of the assignment arrow, otherwise a
LENGTH ERROR is issued:
(a b) ← 23 41 56
LENGTH ERROR (a b)←23 41 56 ∧
9.2.2. Using Parentheses¶
As we have already mentioned in the “Data and Variables” chapter, for clarity and also for compatibility with other APL systems, we recommend that you parenthesise the names of the variables to the left of the arrow. However, this is not mandatory in Dyalog APL and you may come across the following syntax, especially in environments where compatibility with other APL systems is not an issue:
a b c ← 23 41 56
However this is highly discouraged. Using parentheses indicates much more clearly the intent of performing multiple assignment and helps prevent some erroneous behaviour. For example, notice how the expression below raises an error because we are trying to assign
3, and yet,
var gets assigned
var 3 ← 5
SYNTAX ERROR var 3←5 ∧
However, if we use parentheses the assignment is not performed at all:
(var 3) ← 50
SYNTAX ERROR (var 3)←50 ∧
If you still aren’t convinced that unparenthesised multiple assignment is evil, another argument against it is that multiple assignments can be ambiguous to read. For example, what does
a b c ← 42
The ambiguity arises from the fact that the lack of parenthesising means we need to know what
c, are, in order to understand the expression above.
For example, if all three variables are arrays, then we reassign them:
a ← b ← c ← 0
a b c ← 42 ⎕← a b c
c were a function, for example
-, this is what we get:
)erase c c ← - a ← b ← 0
a b c ← 42 ⎕← a b
Unfortunately, at the time of writing, there is no way to use parenthesis to disambiguate the two situations above.
9.3. Selective Assignment¶
9.3.1. Quick Overview¶
Let us consider the following matrix:
⎕← mat ← 3 4⍴13 52 33 81 42 62 70 47 51 73 28 19
It is easy to select (extract) the first row and a half of that matrix:
But, until now, it would have been much more complex to modify these items. Previously, we would have had to use two steps:
mat[1;] ← 37 38 11 12 mat[2;1 2] ← 20 88 mat
Now, we will introduce selective assignment. The purpose of selective assignment is to provide a concise way to specify that a selected part (and only that selected part) of an array is to be assigned a new value. In selective assignment, the expression that specifies (selects) the part of the array to be changed, appears in parentheses to the left of the assignment arrow. The replacement array appears on the right.
Let us restore
mat to its original state, and try out this new technique:
⎕← mat ← 3 4⍴13 52 33 81 42 62 70 47 51 73 28 19 (6⍴mat) ← 37 38 11 12 20 88 mat
It is important to realise that the replacement array does not necessarily have the same shape as the indices of the replaced portion of
mat, which in any case are not necessarily rectangular.
Instead, the replacement array must have the same shape as the result of the selection expression.
In this case,
6⍴mat would have produced a 6-item vector, so the replacement array must be a 6-item vector, too.
This is also true if we select/replace a sub-matrix of
mat using take:
(¯2 3↑mat) ← 2 3⍴10×⍳6 mat
We can even try using a nested replacement array, here using drop:
(1 1↓mat) ← 2 3⍴'To' 'be' 'or' 'not' 'to' 'be' mat
Notice that, unlike multiple assignment, the usage of parentheses is mandatory in selective assignment. If the parentheses are omitted, the selection expression will just act like an expression that is evaluated after the inline assignment.
Compare the value of
(1⍴mat) ← 999 mat
with the value of
1⍴mat ← 888 mat
9.3.2. Available Primitives¶
This technique cannot be used with every single primitive function; only the following selection functions are allowed. When appropriate, these functions can also be used with an axis specification:
⊖: reverse, rotate
⍉: monadic and dyadic transpose
⊃: disclose, pick
Some of the functions listed here haven’t been introduced yet, but will be soon.
One of the most interesting selection tools is compress.
Let us restore
⎕← mat ← 3 4⍴13 52 33 81 42 62 70 47 51 73 28 19
How can we negate all the values which are smaller than 40?
((,mat<40)/,mat) ×← ¯1 mat
We can also use compress to replace vowels scattered throughout a matrix:
⎕← monMat ← 6 8⍴'January FebruaryMarch April May June '
((,monMat∊'aeiouy')/,monMat) ← '_' monMat
Later on, in the chapter about operators, we will learn about another tool that is suitable for this kind of job.
Using dyadic transpose, it is possible to select and modify a diagonal in a matrix.
(1 1⍉mat) ← 0 mat
To replace all the items in a matrix with the values contained in a vector, we now have two methods:
mat ← (⍴mat)⍴⍳12 mat
And the one with selective assignment, using ravel:
(,mat) ← 12+⍳12 mat