Skip to content

Applying functions

Apply functions with bracket, prefix, infix and postfix syntax.

Also with the Apply and Apply At operators.

Functions are first-class entities. They include operators, keywords, iterators, and lambdas.

Noun syntax

A function in parentheses, or in a general or argument list, is an atom and has noun syntax. It is not evaluated when the list is defined.

type (+)            / atom in parens
type[+]             / argument to type
(+;count;{x*x};*\)  / a list of functions

To apply a function to argument values, use bracket syntax.

Bracket syntax

You can always evaluate a function on an argument list.

Argument list

Zero or more items, separated by semicolons, embraced by brackets.

The function maps the given values to its arguments; evaluates its expressions, and returns is result.

q)*[2;3]
6
q),[`ibm;`goog`msft]
`ibm`goog`msft
q)count["quick"]
5
q)ssr["quick brown fox";"br?wn";"brave"] 
"quick brave fox"
q){6*7}[]
42

Infix syntax

Binary functions take two arguments. Binary operators and keywords may be used with infix syntax; lambdas may not.

In infix syntax the function appears between its first and second arguments. There are no square brackets.

q)2*3
6

In infix syntax the function has short left scope and long right scope.

  • Its left (first) argument is the value immediately to its left.
  • Its right argument is the result of evaluating the entire expression to its right.

Example:

q)3 4+2 4 xexp 2
7 20f

Above, the left argument of xexp is 2 4 (because vector literals bind more tightly than anything else) and its right (second) argument is 2.

The left argument of Add is 3 4 and its right argument is the result of evaluating 2 4 xexp 2.

Infix syntax is preferred but optional. The above could also be written:

q)+[3 4;xexp[2 4;2]]
7 20f

You can see why infix syntax is generally better.

Left and right arguments

Good q style prefers infix syntax for binaries. This leads to dubbing the first and second arguments respectively left and right.

The practice is inherited from APL, where functions have no more than two arguments and all binary functions are used infix. The naming convention is extended in q.

Although in q a binary lambda cannot be used infix, the functions that iterators derive from it can, so its arguments might still be dubbed left and right.

left my_fn2'right  <==>  my_fn'[left;right]

For similar reasons, in functions of rank 3–8 the first argument is the left argument, and the others its right arguments.

q) Chinese Whispers
q)left:"Going to advance; please send me reinforcements"
q)right1:("advance";"send";"reinforcements")
q)right2("a dance";"lend";"three and fourpence")
q)ssr\[left;right1;right2]
"Going to a dance; please send me reinforcements"
"Going to a dance; please lend me reinforcements"
"Going to a dance; please lend me three and fourpence"

The sole argument of a unary function appears to its right but is simply its argument; left and right do not apply.

Prefix syntax

Unary functions can be applied with prefix syntax.

q)til 3  / equivalent to til[3]
0 1 2

As with infix syntax

  • the function has long right scope: its argument is the result of evaluating the entire expression to its right
  • prefix syntax is optional but preferred for readability

A republic of functions

There is no hierarchy of functions. None. (So there is nothing to remember.)

As Arthur Whitney points out, every programming language follows this rule when assigning a value to a name: the value assigned to a name is everything to the right of the assignment token.

let a = b * c + d

Like other Iversonian languages (APL, J, k) q is simply consistent about it.

Prefix syntax is sometimes referred to as juxtaposition.

Postfix syntax

The iterators are unary operators with postfix syntax. They have short left scope – and (of course) no right scope.

Adverb syntax

The iterators were originally known as adverbs so in q postfix syntax is sometimes called adverb syntax.

The functions they derive have infix syntax. (See Iterators for more on this.)

q)"gimme ",/:("shelter";"a fiver")
"gimme shelter"
"gimme a fiver"

Above, Join , is the argument of Each Right /:. The derived function Join Each Right ,/: can be used with infix syntax, which is preferred style. Its left argument is "gimme" and its right argument is ("shelter";"a fiver").

As noted for infix syntax, while prefix and postfix syntax are preferred style, neither is required. Bracket syntax always works.

q)show s:string (`gimme`shelter;`cry`me`a`river)
("gimme";"shelter")
("cry";"me";,"a";"river")

q)count s
2
q)count each s  / prefix syntax
2 4
q)count'[s]     / bracket syntax
2 4
q)count''[s]    / bracket syntax
5 7
3 2 1 5

Above, each is not an iterator but a binary keyword with infix syntax; count is its left argument.

In the last example, the argument of the second Each is count' deriving the function count'', which is applied with bracket syntax.

Probably more readable than the keyword equivalent:

(count each) each s

Derived functions can be applied infix

Derived function Join Each ,' retains the infix syntax of Join.

Derived function {[x;y] ...}' enjoys infix syntax even though the lambda does not.

Both count and count' are unary, but the derived function has infix syntax even though it is a unary and using it infix signals a rank error.

A function derived by applying an iterator with postfix syntax has infix syntax.

How to apply the derived function?

q)count'[("quick";"brown";"fox")]        / reliable old bracket syntax
5 5 3

No problem. Bracket syntax always works.

q)2 count' ("quick";"brown";"fox")       / infix syntax – of no use to a unary
'rank
  [0]  2 count' ("quick";"brown";"fox")  ..
              ^

The derived function has infix syntax even though it’s unary. See how 2 count' .. signals a rank error: infix has passed it two argument values but it can use only one.

q)count' ("quick";"brown";"fox")         / prefix syntax fails
'
  [0]  count' ("quick";"brown";"fox")    ..
             ^

The derived function is unary, so we should be able to use prefix, but the parser is looking for a left argument. 😱

There are four remedies.

The first is of course to use the each keyword to take care of it for you. In simple expressions this is usually the best style.

q)count each ("quick";"brown";"fox")  / prefix syntax all right with a noun
5 5 3

The next two remedies tame the wild derived function. Parenthesising it creates a function atom with noun syntax, and nouns can be applied prefix. Or, assigned a name, it loses its infix syntax and can be applied prefix like any other unary.

(As in fairy stories, capturing or naming a weird thing gives you power over it.)

q)(count') ("quick";"brown";"fox")  / capture as a noun
5 5 3
q)ce:count'                         / assign a name
q)ce ("quick";"brown";"fox")
5 5 3

Using bracket syntax to apply an iterator to a unary doesn’t give the derived function infix syntax.

The fourth remedy is to avoid postfix syntax in the first place.

q)'[count] ("quick";"brown";"fox")  / derive with bracket syntax
5 5 3

Exercises

No peeking.

Attempt each exercise before looking at its answer.

The exercises clarify your thinking. Reading answers does not.

Application syntax

  1. Evaluate three expressions that apply unary keywords with prefix syntax. Rewrite the same expressions using bracket syntax and evaluate them to show the same results.

    Answer

    Some examples:

    q)til[4] ~ til 4
    1b
    q)count["abc"] ~ count "abc"
    1b
    q)prev["abc"] ~ prev "abc"
    1b
    
  2. Evaluate three expressions that apply binary operators with infix syntax. Rewrite the same expressions using bracket syntax and evaluate them to show the same results.

    Answer
    q)(+[2;3]~2+3; $[`;"abc"]~`$"abc"; #[3;5]~3#5)
    111b
    
  3. Can you use infix syntax to apply a binary lambda? Define plus:+. Can you apply plus with infix syntax?

    Answer

    No.

    q)plus:+
    q)plus[2;3]
    5
    q)2 plus 3
    'type
      [0]  2 plus 3
           ^
    

  4. Let f be a ternary function. Show the different ways you can apply it to arguments x, y, and z. Demonstrate with a ternary lambda or keyword.

    Answer

    f[x;y;z]           / bracket syntax
    f . (x;y;z)        / Apply operator
    eval (f;x;y;z)     / parse tree
    
    q)ssr["bread";"rea";"ear"]
    "beard"
    q)ssr . ("bread";"rea";"ear")
    "beard"
    q)eval (ssr;"bread";"rea";"ear")
    "beard"
    

Republic of functions

  1. Predict the result of

    2 xexp 3 4 - 2 * 5 - 4
    

    Evaluate the expression and explain the result.

    Answer

    q)2 xexp 3 4 - 2 * 5 - 4
    2 4f
    q)5 - 4
    1
    q)2 * 5 - 4
    2
    q)3 4 - 2 * 5 - 4
    1 2
    q)2 xexp 1 2
    2 4f
    
    Notice that the vector literal 3 4 binds tighter than any other tokens.

  2. Write the same expression using only bracket syntax.

    Answer

    q)xexp[2;-[3 4;*[2;-[5;4]]]]
    2 4f
    
    For clarity, rewrite to remove brackets, parentheses and separators.

  3. Write an expression that evaluates

    \[2^3 . 4 - 2\times 5 - 4\]
    Answer
    q)(((2 xexp 3)*4)-2*5)-4
    18f
    
  4. Rewrite the expression without parentheses.

    Answer
    q)-4 + -[;2*5] 4*2 xexp 3
    18f
    
  5. Find ways to write (a*a)+(2*a*b)+(b*b) without parentheses.

    Answer

    Some possible answers:

    *[a;a]+prd[2,a,b]+*[b;b]
    {sum prd[2,x],x*x}a,b
    sum {x*x}[ab],2*prd ab:a,b
    sum prd each @[;0 3 5_0 1 2 1 1 2 2]2,a,b
    sum 1 2 1*cut[2;2 0 1 1 0 2]{prd"j"$y xexp x}\:ab:a,b
    
    The cure can be worse than the disease.

    Or you can use the power of math.

    {x*x} a+b
    prd 2#a+b
    

Adverb syntax

  1. Iterators can be (and almost always are) applied with postfix syntax. They derive functions. Demonstrate this by defining ce:count' and applying derived function ce to an argument. With what syntax can you apply ce?

    Answer

    q)ce:count'
    q)qbf:string`quick`brown`fox
    q)ce qbf    / prefix
    5 5 3
    q)ce[qbf]   / bracket
    5 5 3
    q)ce@qbf    / Apply At
    5 5 3
    
    Count Each returns the length of each item of its argument.

  2. Define cee:count''. Show what it does. Describe how count'' is parsed and evaluated. Is there a difference between cee, ce', and count''?

    Answer

    q)cee:count''
    q)cee("quick";"brown";"fox")
    1 1 1 1 1
    1 1 1 1 1
    1 1 1
    q)cee 2 2#("quick";"brown";"fox";"jumps")
    5 5
    3 5
    
    Count Each Each returns the length of each item of each item of its argument.

    Above, count' is the argument of '.

    All three are the same:

    q)(count'') ~/: (cee;ce')
    11b
    

  3. Join ,, Join Each ,', and je:,' are all binaries. Show that Join and Join Each can be applied with infix syntax but that je cannot.

    Answer
    q)"ab",2 cut "wxyz"
    "a"
    "b"
    "wx"
    "yz"
    q)"ab",'2 cut "wxyz"
    "awx"
    "byz"
    
    q)je:,'
    q)je["ab";2 cut "wxyz"]      / bracket syntax
    "awx"
    "byz"
    q)"ab" je 2 cut "wxyz"       / infix
    'type
      [0]  "ab" je 2 cut "wxyz"
    
  4. Iterators can be applied with postfix syntax, and almost always should be. Show Each applied to Join with bracket syntax instead. Show that the derived function cannot be applied infix. Assign it the name jev and show that jev cannot be applied infix either.

    Answer
    q)jev:('[,])                     / parens for noun syntax
    q)jev["ab";2 cut "wxyz"]         / apply with bracket syntax
    "awx"
    "byz"
    q)"ab" jev 2 cut "wxyz"          / not with infix syntax
    'type
      [0]  "ab" jev 2 cut "wxyz"
           ^
    
  5. Define a unary lambda and show that the four ways of each-ing a unary function all work for it.

    Answer
    q)el:{$[0>type x;(),x;x]}  / ensure list
    q)el 3
    ,3
    q)el 1 2 3
    1 2 3
    
    q)el each 1 2 3            / each keyword
    1
    2
    3
    q)el'[1 2 3]               / derived fn with bracket syntax
    1
    2
    3
    q)(el') 1 2 3              / derived fn with prefix syntax
    1
    2
    3
    q)'[el] 1 2 3              / derived fn with prefix syntax
    1
    2
    3
    q)'[el] [1 2 3]            / derived fn with bracket syntax
    1
    2
    3