Search code examples
kdb

What is the general pattern behind (dyadic) function composition's syntax?


The Q Tips book (Nick Psaris) shows the following function (Chapter 10):

q)merge:`time xdesc upsert

As it is stated, it corresponds to function composition. I see the pattern: the expression supplies a function that takes both arguments for upsert and then uses its result to feed time xdesc. However the syntax feels weird, since I would expect upsert to be the second argument of the xdesc invocation.

Aiming at simplifying the expression, I could see that the very same scenario applies here:

q)f:1+*
q)f[2;3]
7

If we show its result, we can clearly see that f behaves as expected:

q)f
+[1]*

However, If we slightly modify the function, the meaning of the expression is completely different:

q)g:+[1;]*
q)g[2;3]
'rank
  [0]  g[2;3]
       ^

In fact, +[1;] is passed as first argument to the * operator instead, leading us to a rank error:

q)g
*[+[1;]]

I could also notice that the pattern breaks when the first function is "monadic":

q)h:neg *
q)h[2;3]
'rank
  [0]  h[2;3]
       ^

Also here:

q)i:neg neg
'type
  [0]  i:neg neg
         ^

At this point, my intuition is that this pattern only applies when we are interested on composing dyadic standard (vs user-defined) operators that exploit infix notation. Am I getting it right? Is this syntactic sugar actually more general? Is there any documentation where the pattern is fully described? Thanks!


Solution

  • There are some documented ways to achieve what you wish:

    https://code.kx.com/q/ref/apply/#composition

    You can create a unary train using @

    q)r:neg neg@
    q)r 1
    1
    

    https://code.kx.com/q/ref/compose/

    You can use ' to compose a unary value with another of rank >=1

    q)f:('[1+;*])
    q)f[2;3]
    7
    

    Likely the behaviour you are seeing is not officially there to be exploited by users in q so should not be relied upon. This link may be of interest:

    https://github.com/quintanar401/DCoQ