9. Special Syntax

9.1. Modified Assignment

Changes to a variable, like

a  4

or

languages  'APLL' 'Pithon' 'Jaba'

frequently involve modifying its current value, and such expressions naturally contain two references to its name:

 a  a + 1
5

or

 languages  languages,'Cee' 'Paskal' 'Russt'
┌────┬──────┬────┬───┬──────┬─────┐ │APLL│Pithon│Jaba│Cee│Paskal│Russt│ └────┴──────┴────┴───┴──────┴─────┘
 languageThousandsUsersByYear  4 62562 2435 3254 9843 6234 2634 2345 6543 9875 2452 5645 2345 3411 5462 8787 2435 2435 7634 5632 6543 2345 2345 6486 3452
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
2245 2352 5545 2245 3311 2335 2335 7534

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:

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

9.1.1. Application

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
52 17 39 77 40 17 29 0 0 14 80 12 31 46 100 51 49 43 21 17 18 19 63 61 70 44 0 20 11

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

9.2.1. Introduction

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
a
23
b
41
c
56
(d e f)  (20 61) (2 2⍴⍳4) 'Africa'
d
20 61
e
1 2 3 4
f
Africa

These two instructions are equivalent to the individual assignments a 23, b 41, …

The variables d and 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 a, b, and c (which we have just set to 23, 41, and 56, respectively), as follows:

(a b c) + 57 (19 ¯16) (2 3⍴⍳6)
a b c
┌──┬─────┬────────┐ │80│60 25│57 58 59│ │ │ │60 61 62│ └──┴─────┴────────┘

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 5 to 3, and yet, var gets assigned 5:

var 3  5
SYNTAX ERROR
      var 3←5
           ∧
var
5

However, if we use parentheses the assignment is not performed at all:

(var 3)  50
SYNTAX ERROR
      (var 3)←50
             ∧
var
5

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

do?

The ambiguity arises from the fact that the lack of parenthesising means we need to know what a, b, and 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
42 42 42

However, if c were a function, for example -, this is what we get:

)erase c
c  -
a  b  0
a b c  42
 a b
¯42 ¯42

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 413 52 33 81 42 62 70 47 51 73 28 19
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:

6mat
13 52 33 81 42 62

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
37 38 11 12 20 88 70 47 51 73 28 19

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 413 52 33 81 42 62 70 47 51 73 28 19
(6mat)  37 38 11 12 20 88
mat
13 52 33 81 42 62 70 47 51 73 28 19
37 38 11 12 20 88 70 47 51 73 28 19

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 3mat
20 88 70 51 73 28
(¯2 3mat)  2 310×⍳6
mat
37 38 11 12 10 20 30 47 40 50 60 19

We can even try using a nested replacement array, here using drop:

(1 1mat)  2 3'To' 'be' 'or' 'not' 'to' 'be'
mat
┌──┬───┬──┬──┐ │37│38 │11│12│ ├──┼───┼──┼──┤ │10│To │be│or│ ├──┼───┼──┼──┤ │40│not│to│be│ └──┴───┴──┴──┘

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 mat here:

(1mat)  999
mat
┌───┬───┬──┬──┐ │999│38 │11│12│ ├───┼───┼──┼──┤ │10 │To │be│or│ ├───┼───┼──┼──┤ │40 │not│to│be│ └───┴───┴──┴──┘

with the value of mat here:

1mat  888
mat
888
888

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:

  • : reshape

  • / and : compress/replicate

  • : take

  • : drop

  • ,: ravel

  • : enlist

  • : table

  • and : reverse, rotate

  • : monadic and dyadic transpose

  • : disclose, pick

  • \ and : expand

  • : index

Some of the functions listed here haven’t been introduced yet, but will be soon.

9.3.3. Examples

One of the most interesting selection tools is compress. Let us restore mat again:

 mat  3 413 52 33 81 42 62 70 47 51 73 28 19
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
¯13 52 ¯33 81 42 62 70 47 51 73 ¯28 ¯19

We can also use compress to replace vowels scattered throughout a matrix:

 monMat  6 8'January FebruaryMarch   April   May     June    '
January February March April May June
((,monMat'aeiouy')/,monMat)  '_'
monMat
J_n__r_ F_br__r_ M_rch Apr_l M__ J_n_

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 1mat)  0
mat
0 52 ¯33 81 42 0 70 47 51 73 0 ¯19

To replace all the items in a matrix with the values contained in a vector, we now have two methods:

The obvious:

mat  (mat)⍴⍳12
mat
1 2 3 4 5 6 7 8 9 10 11 12

And the one with selective assignment, using ravel:

(,mat)  12+⍳12
mat
13 14 15 16 17 18 19 20 21 22 23 24