Skip to content

Atomic functions

Many q functions iterate recursively through list or dictionary arguments down to items of some depth.

Where a function recurses to the atoms of an argument, it is atomic in that domain: typically, left-atomic, right-atomic; or simply atomic for all its arguments.

A function that recurses to strings is string-atomic.

Formal definition

Where f is a function, and x is a list of its arguments, .[f;x]~.[f';x].

q).[+;(2;(3 4;5))]
5 6
7
q).[+';(2;(3 4;5))]   / the iterator is unnecessary
5 6
7

Application, projection, and indexing

By extension, for a unary function, f is atomic if f[x]~f'[x].

q)neg (5 2; 3; -8 0 2)
-5 -2
-3
8 0 -2
q)neg each (5 2; 3; -8 0 2)   / the iterator is unnecessary
-5 -2
-3
8 0 -2

Informal definition

A unary is atomic if it applies to both atoms and lists, and in the case of a list, applies independently to every atom in the list. For example, the unary neg is atomic. A result of neg is just like its argument, except that each atom in an argument is replaced by its negation.

q)neg 3 4 5
-3 -4 -5
q)neg (5 2; 3; -8 0 2)
-5 -2
-3
8 0 -2

neg applies to a list by applying independently to every item. Accessing the ith item of a list x is denoted by x[i] , and therefore the rule for how neg applies to a list x is that the ith item of neg x, which is (neg x)[i], is neg applied to the ith item.

neg can be defined recursively for lists in terms of its definition for atoms. To do so we need two language constructs.

  • Any function f can be applied independently to the items of a list by modifying the function with the Each iterator, as in f'.
  • The function {0>type x} has the value 1 when x is an atom, and 0 when x is a list.

Using these constructs, neg can be defined as follows:

neg:{$[0>type x; 0-x; neg'[x]]}

That is, if x is an atom then neg x is 0-x, and otherwise neg is applied independently to every item of the list x. One can see from this definition that neg and neg' are identical. In general, this is the definition of atomic: a function f of any number of arguments is atomic if f is identical to f'.

A binary f is atomic if the following rules apply (these follow from the general definition that was given just above, or can be taken on their own merit):

  • f[x;y] is defined for atoms x and y
  • for an atom x and a list y, the result f[x;y] is a list whose ith item is f[x;y[i]]
  • for a list x and an atom y, the result f[x;y] is a list whose ith item is f[x[i];y]
  • for lists x and y, the result f[x;y] is a list whose ith item is f[x[i];y[i]]

For example, the operator Add is atomic.

q)2 + 3                      q)2 6 + 3 
5                            5 9
q)2 + 3 -8                   q)2 6 + 3 -8 
5 -6                         5 -2

q)(2; 3 4) + ((5 6; 7 8 9); (10; 11 12))
7 8 9 10 11
13  15 16

In the last example both arguments have count 2. The first item of the left argument, 2, is added to the first item of the right argument, (5 6; 7 8 9), while the second argument of the left argument, 3 4, is added to the second argument of the right argument, (10; 11 12). When adding the first items of the two lists, the atom 2 is added to every atom in (5 6; 7 8 9) to give (7 8; 9 10 11), and when adding the second items, 3 is added to 10 to give 13, and 4 is added to both atoms of 11 12 to give 15 16.

Add can be defined recursively in terms of Add for atoms as follows:

q)Add:{$[(0>type x) & 0>type y; x + y; Add'[x;y]]}

Length and type

The arguments of an atomic function must be conformable.

q)1 2 3 + 4 5
'length
  [0]  1 2 3 + 4 5
             ^

Type errors can arise at depth.

q)1 2 3 + (4;"a";5)
'type
  [0]  1 2 3 + (4;"a";5)
             ^

Rank

Atomic functions are not restricted to ranks 1 and 2. For example, the ternary {x+y xexp z} (“x plus y to the power z”) is atomic.

Left- and right-atomic

A function can be atomic relative to some of its arguments but not all. For example, the Index At operator @[x;y] is an atomic function of its right argument but not its left, and is said to be right-atomic, or atomic in its second argument. That is, for every left argument x the projected unary function x@ is atomic. This primitive function, like x[y], selects items from x according to the atoms in y, and the result is structurally like y, except that every atom in y is replaced by the item of x that it selects.

q)2 4 -23 8 7 @ (0 4 ; 2)
2 7
-23

Index 0 selects 2; index 4 selects 7; and index 2 selects -23.

String-atomic

Q does not have a string datatype. What we call strings are char vectors.

Some functions that apply to strings recurse until they find either strings or char atoms. They are string-atomic.

q)upper ("quick";("brown";"fox");"x")
"QUICK"
("BROWN";"FOX")
"X"

Q for Mortals §6.6 Atomic Functions