Adverbs

Adverbs are primitive higher-order functions: they return derived functions, known as derivatives. They are much used for iteration.

q)+/[2 3 4]      /reduce 2 3 4 with +
9
q)*/[2 3 4]      /reduce 2 3 4 with *
24

Adverb syntax, .Q.fu (apply unique)

form adverb semantics
int'[x;y;…] case select from [x;y;…]
'[f;g][x;y;…] compose compose f with g
x f'y each-both apply f between items of x and y
x f\:y each-left apply f between y and items of x
x f/:y each-right apply `f betweenxand items ofy`
f':x each-parallel apply f to items of x in parallel tasks
f':x each-prior apply f between successive pairs of items of x
f/x converge apply f to x until converges
x f/y repeat apply f to y, x times or while x
x f/y over reduce y with f
f/[x;y;…] fold reduce [x;y;…] with f
f\x converge apply f to x until converges
x f\y iterate apply f to y, x times or while x
f\x scan apply f/ to successive items of x

Key: int: int vector; f: function; g: function; x: data; y: data.

' (case)

case

Pick successive items from multiple list arguments: the left argument of the adverb determines from which argument of the derivative each item is picked.

Syntax: d:x' (unary, postfix)
Derivative: d y (multivalent)

Where x is an integer vector and \(args\) are the arguments to the derivative, the derivative x' returns \(r\) such that \(r_i\) is (\(args_{x_i})_i\)

Atom arguments in y are treated as infinitely-repeated values.

q)0 1 0'["abc";"xyz"]
"ayc"
q)e:`one`two`three`four`five
q)f:`un`deux`trois`quatre`cinq
q)g:`eins`zwei`drei`vier`funf
q)l:`English`French`German
q)l?`German`English`French`French`German
2 0 1 1 2
q)(l?`German`English`French`French`German)'[e;f;g]
`eins`two`trois`quatre`funf

q)/extra arguments don't signal a rank error
q)0 2 0'["abc";"xyz";"123";"789"]
"a2c"
q)0 1 0'["a";"xyz"]  /atom "a" repeated as needed
"aya"

Case is useful for selecting between record fields according to a test on some other field.

Suppose we have lists h and o of home and office phone numbers, and a third list p indicating at which number the subject prefers to be called.

q)([]pref: p;home: h; office: o; call: (`home`office?p)'[h;o])
pref   home             office           call
---------------------------------------------------------
home   "(973)-902-8196" "(431)-158-8403" "(973)-902-8196"
office "(448)-242-6173" "(123)-993-9804" "(123)-993-9804"
office "(649)-678-6937" "(577)-671-6744" "(577)-671-6744"
home   "(677)-200-5231" "(546)-864-5636" "(677)-200-5231"
home   "(463)-653-5120" "(636)-437-2336" "(463)-653-5120"

' (compose)

Syntax: d:'[g;f] (binary, prefix)
Derivative: d[x;y;z;…] (same rank as f)

Where f is a multi-argument function and g is a unary function, the derivative f' has rank f and returns g f[x;y;z;…].

q)f:{[w;x;y;z]w+x+y+z}
q)g:{2*x}
q)d:('[g;f])               / The interpreter is finicky about :'
q)d[1;2;3;4]               / g f[1;2;3;4]
20

Compose a list of functions

This can be extended with over to compose a list of functions.


q)g1:{10*x}
q)d1:('[;]) over (g1;g;f)  / Use ('[;]) so the correct form is used
q)d1[1;2;3;4]
200

each-both

' (each-both)

Applies a function between corresponding items of the argument lists.

Syntax: d:f' (unary, postfix)
Derivative: x d y (binary, uniform)

Where f is a binary function, and x and y conform, the derivative f' applies f between corresponding items of x and y.

q)0 1 2 3 ,' 10 20 30 40
0 10
1 20
2 30
3 40

If either x or y is atomic, it is paired to every item in the other argument.

q)0 1 2 3 ,' 10
0 10
1 10
2 10
3 10

each-left

\: (each-left)

Applies a function between each item of the left argument and the right argument.

Syntax: d:f\: (unary, postfix)
Derivative: x d y(binary, uniform)

Where f is a binary function, the derivative f\: applies f between y and each item of x where

  • x is a list
  • y is an atom or a list
q)(til 5),\:0 1
0 0 1
1 0 1
2 0 1
3 0 1
4 0 1

each-right

/: (each-right)

Applies a function between the left argument and each item of the right argument.

Syntax: d:f/: (unary, postfix)
Derivative: x d y (binary, uniform)

Where f is a binary function, the derivative f/: applies f between x and each item of y where

  • x is an atom or a list
  • y is a list
q)(til 5),/:0 1
0 1 2 3 4 0
0 1 2 3 4 1

Left, right, cross

Each-left combined with each-right


q){}0N!(til 4),\:/: til 4
((0 0;1 0;2 0;3 0);(0 1;1 1;2 1;3 1);(0 2;1 2;2 2;3 2);(0 3;1 3;2 3;3 3))    
resembles the result obtained by cross

q){}0N!cross[til 4;til 4]
(0 0;0 1;0 2;0 3;1 0;1 1;1 2;1 3;2 0;2 1;2 2;2 3;3 0;3 1;3 2;3 3)

each-parallel

': (each-parallel)

Each item of the argument list is assigned to a slave task, where the function is applied to each of its items.

Syntax: d:f': (unary, postfix)
Derivative: d x (unary, uniform)

Where f is a unary function, the derivative f': assigns the items of x to separate slave tasks, and in each task applies f to each item of the sublist.

$ q -s 2
KDB+ 3.4 2016.06.14 Copyright (C) 1993-2016 Kx Systems
m32/ 2()core 4096MB sjt mark.local 192.168.0.17 NONEXPIRE
q)\t ({sum exp x?1.0}' )2#1000000  / each
185
q)\t ({sum exp x?1.0}':)2#1000000  / peach
79
q)peach
k){x':y}

command-line options, parallel processing, peach

Projecting a unary function with apply

You can use apply . to project a binary or higher-rank function as a unary function of a list of its arguments. The projection can then be combined with an adverb (such as each-parallel or converge-iterate) that takes a unary function as its argument.


q)f2:{(0|x-1;x rotate y)} / binary fn, returns 2-list
q)f1:f2 .                 / unary fn of a 2-list
q)f1\[(4;"hello")]        / converge-iterate
4 "hello"
3 "ohell"
2 "llohe"
1 "ohell"
0 "hello"
Note that for converge-repeat and converge-iterate, the function must return a list of the same length as its rank.

each-prior

': (each-prior)

Applies a function between each item of a list and its preceding item.

Syntax: d:f': (unary, postfix)
Derivative: d y (unary, uniform)
Derivative: x d y (binary, uniform)

Where f is a binary function, the ambivalent derivative f': applies f between each item of y and x,-1_y.

In unary application of the derivative, x defaults to (1#0#y)0.

q)99,':til 4
0 99
1 0
2 1
3 2
q)(,':)til 4  / x defaults to 0N
0
1 0
2 1
3 2
q)"abc",':"xyz"
"xabc"
"yx"
"zy"
q)0 1-':2 5 9
2 1
3
4
q)0-':2 5 9
2 3 4
q)-':[2 5 9]     /deltas
2 3 4
form example
f':[y] -':[   1 4 9 16] /unary
(f':)y (-':)  1 4 9 16 /juxtaposition
x f': y 9-':   1 4 9 16 /infix (binary)
f':[x;y] -':[9; 1 4 9 16] /prefix (binary)
f':[x;]y -':[9;]1 4 9 16   /projection

St Patrick driving the snakes out of Ireland
Are we there yet?

/ (converge-repeat)

Applies a function either a specified number of times, or until the result converges.

Syntax: d:f/ (unary, postfix)
Derivative: d y (unary)
Derivative: x d y (binary)

Where f is a unary function, the derivative f/

  • (converge) applied unary applies f repeatedly to y until either (1) two successive results agree within comparison tolerance or (2) the result matches y. The latter will save you from some infinite cycles but not all.

    
    q)(not/) 1b
    0b
    q)(not/) 42  /never returns
        
    The related form converge-iterate can be useful to see the intermediate results. (Set \P 0 to see the convergence of your original computation.)

  • (repeat) applied binary where (a) x is a positive int atom, returns the result of x successive applications of f to y f f f … f f y

    
    /first 10+2 numbers of Fibonacci sequence
    q)10{x,sum -2#x}/0 1             / derived binary applied infix
    0 1 1 2 3 5 8 13 21 34 55 89
    /first n+2 numbers of Fibonacci sequence
    q)fibonacci:{x,sum -2#x}/[;0 1]  / projection of derived function
    q)fibonacci 10
    0 1 1 2 3 5 8 13 21 34 55 89
    

    or where (b) x is a function, returns the result when x applied to the result returns 0b.

    
    q){x+x}/[{x<1000};2]   /prefix: f/[g;y]
    1024
    q){x<1000}{x+x}/2      /infix: g f/y
    1024
    

over

/ (over)

Map-reduce: applies a binary function between elements of the argument, working from left to right.

Syntax: d:f/ (unary, postfix)
Derivative: x d y (ambivalent, aggregate)

Where f is a binary function

f/[y]
f[f[…f[f[y0;y1];y2];…yn-1];yn]
f/[x;y]
f[f[…f[f[x;y0];y1];…yn-1];yn]
q)(+/)2 3 4  /unary
9
q)0+/2 3 4   /binary
9
q)-/[8 1 9 5 4]
-11

ambivalent derivatives, over operator.

/ (fold)

Over (map-reduce) for functions with more than two arguments.

Syntax: d:f/ (unary, postfix)
Derivative: d[x;y;z;…] (same rank as f)

Where f is a function with rank above 2 and y, z, etc. conform, the derivative f/ has the same rank as f. Example: for f of rank 3 and y and z of count n)

f/[x;y;z]
f[f[… f[f[x;y0;z0];y1;z1]; … yn-1;zn-1];yn;zn]
q){x+y+z}/[1 5 6;2 22;3 33]
61 65 66

Fold and over

Over is fold as applied to a binary function.

\ (converge-iterate)

Syntax: d:f\ (unary, postfix)
Derivative: d y (unary)
Derivative: x d y (binary)

Where f is a unary function, the derivative f\

  • (converge) applied unary calls f on y repeatedly until a value matching the y or the last result is produced. The result is y followed by all the results except the last.
q)(neg\)1
1 -1
q)(rotate[1]\)"abcd"
"abcd"
"bcda"
"cdab"
"dabc"
q)({x*x}\)0.1
0.1 0.01 0.0001 1e-08 1e-16 1e-32 1e-64 1e-128 1e-256 0
q){x*x}\[0.1]   / alternative syntax
0.1 0.01 0.0001 1e-08 1e-16 1e-32 1e-64 1e-128 1e-256 0
  • (iterate) applied binary, x can be either an integer number of iterations or a while-condition that returns an int or boolean which can be applied to the result of f.
q)f:1+
q)f\[3;100]
100 101 102 103
q)f\[105>;100]
100 101 102 103 104 105
q)f\[105>sum@;84 20]
84 20
85 21
q)3 f\100 /applied infix
100 101 102 103

\ (scan)

Syntax: d:f\ (unary, postfix)
Derivative: d y (unary, uniform)
Derivative: x d y (binary, uniform)
Derivative: d[x;y;z;…] (uniform)

Where f is a binary function, the derivative f\ applies f/ to successive items of x. Its result is a list of the same count, built up as follows:

r0 = x0
ri = f[ri-1;xi] for i > 0

Where f\ is applied

  • unary
q)(+\)til 10
0 1 3 6 10 15 21 28 36 45
q)+\[til 10]
0 1 3 6 10 15 21 28 36 45
  • binary, x is used as the initial value.
q)1+\1 2 3
2 4 7
q)+\[1;1 2 3]
2 4 7
  • >rank 2, x is used as the initial value and other arguments are corresponding items from the lists.
q){(x;y;z)}\[0;1 2 3;4 5 6]
0           1 4
0 1 4       2 5
(0 1 4;2;5) 3 6

As of V3.1 2013.07.07, scan has a built-in function for the following.

q){{z+y*x}\[x;y;z]}
{{z+y*x}\[x;y;z]}
q){x y\z}           /alternative syntax using built-in function

Note that for the built-in version it is for floats.

/ over adverb, over operator, scan operator

Derivatives

The semantics of a derivative – what it does – is determined by

  • the rank of the adverb’s function argument/s
  • how the derivative is applied

Some derivatives are ambivalent, and what they do depends on whether they are applied as unary or binary functions. Most binary derivatives can be applied infix, e.g. 2+/3 4 5. A named derivative, e.g. total:+/ retains its ambivalence, but cannot be applied infix.

q)+/[2;3 4 5] ~ 2+/3 4 5  /prefix or infix
1b
q)total:+/
q)total[3 4 5]    /unary (not a projection)
12
q)total[2;3 4 5]  /binary
14
q)2 total 3 4 5   /but not infix
'type
  [0]  2 total 3 4 5
       ^

Projecting an ambivalent derivative

Applying a binary function to one argument projects it on that argument: treble:*[3]. Ambivalent derivatives behave differently.


q)+/[2 3 4]  /applied unary
9
An ambivalent derivative can still be projected using the full form.

q)tenandsum:+/[10;]
q)tenandsum 2 3 4
19