Search code examples
kdb

Mapping a unary function to a list - why is `each` not always required?


I am going through a tutorial on q. Here is the initial setup.

buys:2 1 4 3 5 4
sells:2 4 3 2

I then defined the following function

f:{x & (sums buys)}

I tried to use it in

f (sums sells)

But I get the following error

'length
  [1]  f:{x & (sums buys)}

I note that if instead I do this, it works

q)f each (sums sells)
2 2 2 2  2  2
2 3 6 6  6  6
2 3 7 9  9  9
2 3 7 10 11 11

However, the following unary function outputting a list has no problem being applied

q){(x*x;x)} (1 2 3)
1 4 9
1 2 3

The type signature of the 2 functions seems to be the same to me. Why does one get evaluated while the other raises an error?


Solution

  • It's detailed somewhat in q for mortals here: https://code.kx.com/q4m3/4_Operators/#45-greater-and-lesser

    Specifically "Being atomic they operate item-wise on lists...."

    Generally, kdb/q wants to do list operations itemwise, e.g.

    q)1 2+2 3
    3 5
    

    If you give it lists of different length:

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

    it doesn't know if you want to do

    q)1 2+\:1 2 3
    2 3 4
    3 4 5
    

    or

    q)1 2+/:1 2 3
    2 3
    3 4
    4 5
    

    Same applies to & in your case.

    Your other function is not comparable because the only itemwise operation it does x*x is on lists of the same length. So that's ok.