KX Community

Find answers, ask questions, and connect with our KX Community around the world.
KX Community Guidelines

Home Forums kdb+ Underneath q is k

  • Underneath q is k

    Posted by dhodgins on August 1, 2022 at 12:00 am

    The .q namespace contains all the bits of q which are are wrappers of k and hence gives us a good starting point.

    If we type lj we can see its definition, .q.lj is the fully qualified name.

    q)lj k){$[$[99h=@y;(98h=@!y)&98h=@. y;()~y];.Q.ft[,:[;y];x];'”type”]}

    In order to understand this we need to know what @ and ! mean in k.

    So lets take .q namespace, and filter out all the functions, this gives us a good starting point for translating q into k.(I have manually rearranged the results to group similar things together)

    c 2000 200 
    q)where[1_not type'[.q]in -10 100 106 110h]#.q 
    neg | -: 
    not | ~: 
    hdel | ~: 
    null | ^: 
    string | $: 
    mmu | $ 
    reciprocal| %: 
    ltime | %: 
    floor | _: 
    and | & 
    or | | 
    lsq | ! 
    inv | !: 
    key | !: 
    count | #: 
    first | *: 
    reverse | |: 
    distinct | ?: 
    group | =: 
    where | &: 
    flip | +: 
    type | @: 
    get | .: 
    value | .: 
    hclose | >: 
    sums | + 
    prds | * 
    mins | & 
    maxs | | 
    fills | ^ 
    deltas | -': 
    ratios | %': 
    raze | ,/ 
    read0 | 0:: 
    read1 | 1:: 
    ceiling | -_-: 
    prev | :': 
    union | ?, 
    differ | $["b"]~~': 
    all | min$["b"] 
    any | max$["b"] 
    upsert | .[;();,;] 
    hsym | $["s"]!'[-1] 
    system | .,["\"] 
    md5 | ![-15] 
    attr | ![-2] 
    hcount | ![-7] 
    eval | ![-6] 
    reval | ![-24]

    There are 5 categories. We already excluded lambdas, aliases of internals like -15!, projections like ceiling(neg floor neg@), named adverb’ed operators like sums, and the k operators.

    Both get and value map to the same k operator which is why they are used interchangeably when people write code. Many of the operators are overloaded like ! which does both inv and key depending on the input.

    In k we use a trailing : to indicate that the operator is being used in its monadic form. The : is only required when the statement is ambiguous, the alternative to using : is to use @ or () eg:

    q)k)3=4 /dyadic 
    0b 
    q)k)3=4 3 4 5 4 /dyadic 
    01000b 
    q)k)=:4 3 4 5 4 /monadic explicit 
    4| 0 2 4 
    3| ,1 
    5| ,3 
    q)k)=4 3 4 5 4 /monadic implicit 
    4| 0 2 4 
    3| ,1 
    5| ,3 
    q)k)`a`b`c`d`e=4 3 4 5 4 /used dyadically even though only the monadic form makes sense 
    'type [0] 
    k)`a`b`c`d`e=4 3 4 5 4 ^ 
    q)k)`a`b`c`d`e=:4 3 4 5 4 /: can't be used like this as it like an inplace modification(like +:) 
    'assign [0] 
    k)`a`b`c`d`e=:4 3 4 5 4 ^ 
    q)k)`a`b`c`d`e =:4 3 4 5 4 /Space doesn't help 
    'assign [0] 
    k)`a`b`c`d`e =:4 3 4 5 4 ^ 
    q)k)`a`b`c`d`e@=4 3 4 5 4 /We can explicitly index using @ or [] 
    4| `a`c`e 
    3| ,`b 
    5| ,`d 
    q)k)`a`b`c`d`e(=:)4 3 4 5 4 /We can use round brackets and : 
    4| `a`c`e 
    3| ,`b 
    5| ,`d 
    q)k)`a`b`c`d`e(=)4 3 4 5 4 /Or just round brackets 
    4| `a`c`e 
    3| ,`b 
    5| ,`d

    There are a few k operators missing from .q because they have no alias.

    q)enlist 3

    ,3

    q)k),3 ,3

    enlist and , are similar in what they do, but enlist is written in c. enlist is also variadic unlike ,

    q)enlist[3;4;5] 
    3 4 5 
    q)k),[3;4;5] 
    'rank [0] 
    k),[3;4;5]

    Some of the k operators have been wrapped into functions to add more protection/flexibility. eg til is actually ! but it checks the argument is the correct type.

    q)til k){$[0>@x;!x;'`type]} 
    q)til`a 
    q)til 1 2 
    'type [0] 
    til 1 2 ^ 
    q)k)!1 2 `long 
    q)k)!1 2h `short

    upsert and set are very similar:

    q)upsert .[;();,;] 
    q)set k){$[@x;.[x;();:;y];-19!((,y),x)]}

    upsert appends with , whereas set overwrites with :. set also checks the type of the input and compresses it with -19! if you give a list as the left hand argument.

    As q has a many to one relationship with k it is difficult to reverse the translation, but we can generate a rough lookup table:

    q)group where[1_not type'[.q]in -10 100 106 110h]#.q 
    -: | ,`neg 
    ~: | `not`hdel 
    ^: | ,`null 
    $: | ,`string 
    %: | `reciprocal`ltime 
    _: | ,`floor 
    -_-: | ,`ceiling 
    & | ,`and 
    | | ,`or 
    $ | ,`mmu 
    ! | ,`lsq 
    !: | `inv`key 
    ![-15] | ,`md5 
    #: | ,`count 
    *: | ,`first 
    min$["b"] | ,`all 
    max$["b"] | ,`any 
    + | ,`sums 
    * | ,`prds 
    & | ,`mins 
    | | ,`maxs 
    ^ | ,`fills 
    -': | ,`deltas 
    %': | ,`ratios 
    $["b"]~~': | ,`differ 
    :': | ,`prev 
    |: | ,`reverse 
    ?: | ,`distinct 
    =: | ,`group 
    &: | ,`where 
    +: | ,`flip 
    @: | ,`type 
    .: | `get`value 
    ![-2] | ,`attr 
    .[;();,;] | ,`upsert 
    ,/ | ,`raze 
    ?, | ,`union 
    0:: | ,`read0 
    1:: | ,`read1 
    >: | ,`hclose 
    $["s"]!'[-1]| ,`hsym 
    ![-7] | ,`hcount 
    .,["\"] | ,`system 
    ![-6] | ,`eval 
    ![-24] | ,`reval

    In order to include all the functions such as lj, it is even simpler but i won’t print the whole output for brevity.

    q)group 1_.q -:| ,`neg ~:| `not`hdel ^:| ,`null $:| ,`string %:| `reciprocal`ltime

    If we look at the .Q namespace, we can see it is all written in k. In .Q.ps which is the function that runs select queries on partitioned and segmented tables we can see that in k we can use either newline(n) or ; to terminate a statement, hence the 4 lines don’t end in ; as you might have expected.

    q).Q.ps k){[t;c;b;a]if[-11h=@t;t:. t];if[~qe[a]&qe[b]|-1h=@b;’`nyi];d:pv;v:$[q:0>@b;0;~#b;0;-11h=@v:*. b;pf~*`:v;0] if[$[~#c;0;@*c;0;-11h=@x:c[0]1;pf~*`:x;0];d@:&-6!*c;c:1_c] if[$[#c;0;(g:(. a)~,pf)|(. a)~,(#:;`i)];f:!a;j:dt[d]t;if[q;:+f!,$[g;?d@&0<j;,+/j]];if[v&1=#b;:?[+(pf,f)!(d;j)[;&0<j];();b;f!,(sum;*f)]]] if[~#d;d:pv@&pv=*|pv;c:,()];f:$[q;0#`;!b];g:$[#a;qa@*a;0] $[(1=#d)|$[q;~g;u&pf~*. b];$[~q;.q.xkey[f];b;?:;::]foo[t;c;b;a;v]d;(?).(foo[t;c;$[q;()!();b];*a;v]d;();$[q;0b;f!f];*|a:$[g;ua a;(a;$[#a;(,/;)’k!k:!a;()])])]}

    The other difference between k and q are the rules around what constitutes a symbol. I’m unsure whether there is a reasonable justification for this. Personally I think it is stupid.

    Often when you need help or want to debug you take a variable(or copy the error) and copy it into another q process or skype|teams|outlook however -3! prints in k format and k doesn’t allow _ in symbols so you have to cast them from strings.

    q)tab:([]f:`:dave_hodgins.txt`:jim_bob.txt;("london";"wherever");4 5) 
    q)tab 
    f x x1 
    ------------------------------- 
    :dave_hodgins.txt "london" 4 
    :jim_bob.txt "wherever" 5 
    
    q)-3!tab "+`f`x`x1!(`:dave_hodgins.txt`:jim_bob.txt;("london";"wherever");4 5)" /Need to unescape the double quotes 
    q)k)+`f`x`x1!(`:dave_hodgins.txt`:jim_bob.txt;("london";"wherever");4 5) 
    '( [0] k)+`f`x`x1!(`:dave_hodgins.txt`:jim_bob.txt;("london";"wherever");4 5) 
    k)+`f`x`x1!(`:dave_hodgins.txt`:jim_bob.txt;("london";"wherever");4 5) ^ 
    q)-1@-3!tab; +`f`x`x1!(`:dave_hodgins.txt`:jim_bob.txt;("london";"wherever");4 5) /need to cast to symbol due to different rules 
    q)k)+`f`x`x1!(`:dave_hodgins.txt`:jim_bob.txt;("london";"wherever");4 5) 
    'bob.txt [0] 
    k)+`f`x`x1!(`:dave_hodgins.txt`:jim_bob.txt;("london";"wherever");4 5) ^ /Ugh, so ugly! 
    q)k)+`f`x`x1!(`$(":dave_hodgins.txt";":jim_bob.txt");("london";"wherever");4 5) 
    f x x1 
    ------------------------------- 
    :dave_hodgins.txt "london" 4 
    :jim_bob.txt "wherever" 5

    Finally you can also write k inside q code by surrounding it with round brackets, or by using square brackets:

    q)`a`b!(1 2;3 4) 
    a| 1 2 
    b| 3 4 
    
    q)flip`a`b!(1 2;3 4) 
    a b 
    --- 
    1 3
    2 4 
    
    /q doesn't know what +: is 
    q)+:`a`b!(1 2;3 4) 
    '+: 
    [0] +:`a`b!(1 2;3 4) ^ 
    q)(+:)`a`b!(1 2;3 4) 
    a b 
    --- 
    1 3 
    2 4 
    
    q)+:[`a`b!(1 2;3 4)] 
    a b 
    --- 
    1 3 
    2 4

     

     

    dhodgins replied 2 months, 2 weeks ago 1 Member · 0 Replies
  • 0 Replies

Sorry, there were no replies found.

Log in to reply.