How does each-both (aka multivalent each) work?

Short answer: It takes a function of N operands and creates a new function that applies the original to each set of corresponding elements from N same-length vectors.


We can categorize the ways in which q handles vectors into the following three groups:

  1. Treat the vector as a single entity.

  2. Perform an operation on each element of a vector.

  3. Perform an operation on each set of corresponding elements from multiple vectors of the same length.

We use ‘ (each-both) to ask q to apply a function in the third manner.

Let’s review a few examples to distinguish the three forms of vector handling described above. Consider the , (join) operator, which takes two arguments and concatenates them. When used by itself, , (join) treats a vector as a single entity:

q)1 , 2
1 2
q)1 2 3 , 10
1 2 3 10
q)1 , 10 20 30
1 10 20 30
q)1 2 , 10 20 30
1 2 10 20 30
q)

Notice that the lengths of the two vectors to be joined doesn’t matter; in fact, they don’t have to be vectors.

Next, as an example of applying the same operation to each element of a vector, we can use \: (each-left) to append the letter “e” to each element in a vector of strings:

q)("car"; "far"; "mar") ,\: "e"
"care"
"fare"
"mare"
q)

Lastly, we’ll use ‘ (each-both) to join corresponding elements from two vectors of the same length (like zip from Python or Haskell):

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

As an aside, the use of ‘ (each-both) is not needed for many built-in functions in q, because those functions (sometimes referred to as atomic functions in kx documentation) automatically assume that this is the desired behavior when presented with same-length vectors as arguments. The + operator is a good example:

q)1 2 3 + 10 20 30
11 22 33
q)

Even a user defined function, if that function’s body is exclusively made up of applications of atomic functions, does not require the use of ‘ (each-both) to display this behavior:

q)atomic: {[x; y] (x * x) + y * y}
q)atomic'[1 2 3; 10 20 30]
101 404 909
q)atomic[1 2 3; 10 20 30]  // ' not required
101 404 909
q){[x; y] atomic[x; y]}[1 2 3; 10 20 30]
101 404 909
q)

The last example shows that such user defined atomic functions are truly atomic in the eyes of q.

The following code simulates the behavior of ‘ (each-both) – on functions of two arguments – by creating a new function (that acts on vectors) from the function passed as an argument:

However, ‘ (each-both) doesn’t stop at two lists, which is why it is sometimes called multivalent each. Suppose we need to generate a bunch of html hyperlinks for a web page we are creating on-the-fly (perhaps in a custom http POST handler). Each link needs to have its own styling, so we want to add a distinct class attribute to each anchor tag.

The .h namespace includes numerous functions for generating HTML. The one we need is the .h.htac (html tag with attributes and closing tag) function:

 

q).h.htac[`a; `class`href ! ("myclass"; "kdbfaq.com"); "kdbfaq"]
"<a class=\"myclass\" href=\"kdbfaq.com\">kdbfaq</a>"
q)

Let’s wrap .h.htac (html tag with attributes and closing tag) up in a function to create a styled link:

 

We’ll store the information we need to generate the links in a table:

 

q)links
name        url                    class
----------------------------------------
"kx"        "http://kx.com"        "c1"
"Wikipedia" "http://wikipedia.com" "c2"
"kdbfaq"    "http://kdbfaq.com"    "c3"
q)

Now we can use ‘ (multivalent each) to generate all the links easily:

q)styled_link'[links `name; links `url; links `class]
"<a class=\"c1\" href=\"http://kx.com\">kx</a>"
"<a class=\"c2\" href=\"http://wikipedia.com\">Wikipedia</a>"
"<a class=\"c3\" href=\"http://kdbfaq.com\">kdbfaq</a>"
q)

Or, alternately, we can combine ‘ (multivalent each) with . (apply) for a shorter, more general approach to applying a function to each row in a table:

q)styled_link .' flip value flip links
"<a class=\"c1\" href=\"http://kx.com\">kx</a>"
"<a class=\"c2\" href=\"http://wikipedia.com\">Wikipedia</a>"
"<a class=\"c3\" href=\"http://kdbfaq.com\">kdbfaq</a>"
q)

On more wrinkle: sometimes ‘ (each) is used where \: (each-left) or /: (each-right) would be more explicit. For instance, our earlier example in which we appended the letter “e” to each element of a list of strings could have been written as follows:

q)("car"; "far"; "mar") ,' "e"
"care"
"fare"
"mare"
q)

We find the original, more explicit form, quicker and easier to read.