Core Concepts
q Terminology
A concise glossary of core q vocabulary — functions, rank, operators, iterators, projections, apply, and composition.
You can write a lot of q without knowing this vocabulary. But once you start working with iterators, projections, compositions, and the functional forms of qSQL, these terms appear constantly — and reading documentation or production code becomes much easier once they're familiar.
Note: This page summarizes the terminology most useful for day-to-day q development. For complete definitions, see the code.kx reference and Q for Mortals.
Function
A function maps one or more arguments to a result. Every function in q is either a primitive — built into the language — or built from primitives:
Function
├── Primitive — built into q
│ ├── Operator + - % & | ...
│ ├── Keyword sum count avg ...
│ └── Iterator ' / \ ':
│
└── Built from primitives
├── Derived function +/ (iterator applied to a function)
├── Lambda {x+y}
├── Projection f[10;;]
└── Composition neg sum (a "train" of functions)The rest of this page works through each of these in turn. The most common way to create your own function in q is with a lambda.
Lambda
A lambda is a user-defined function written inside {}:
{x+y} / add two numbers
{x*x} / square a numberThe implicit argument names are x, y, and z — these are the only names q recognises automatically. For more control, or more than three arguments, write an explicit signature inside [...] at the start:
{[a;b] a+b} / name arguments freely, up to 8
{[a;b;c;d] a+b+c+d}A lambda with a signature is called signed. A lambda without a signature is called unsigned. Expressions inside {} are separated by ;, and the value of the last expression is returned.
Argument & Rank
An argument is an input to a function. In a lambda, arguments are named x, y, z — or whatever names appear in its signature:
{x+y}[10;4] / x:10, y:4 -> 14A function's rank is the number of arguments it takes:
| Rank | Name | Example |
|---|---|---|
| 0 | Nullary | {42} |
| 1 | Unary | neg |
| 2 | Binary | + |
| 3 | Ternary | ssr |
| 4 | Quaternary | {[a;b;c;d] a+b+c+d} |
| Variable | Variadic | @ |
A variadic function accepts a variable number of arguments — common with iterators and derived functions.
Operator & Keyword
An operator is a primitive binary function that can be written infix as well as prefix/bracket, e.g. +, -, %, &, |:
1+2 / infix
+[1;2] / bracket form — same resultA keyword is a built-in function written as a word rather than a symbol: sum, count, avg, deltas, mod. Unary keywords such as sum are applied prefix or with brackets — 1 2 3 sum isn't valid. Binary keywords such as mod, within and xbar can also be applied infix, like operators: 10 mod 3.
Both operators and keywords are built into q — the difference is in how they're written and applied.
Iterator
Think of an iterator as a function modifier: applied to a function, it returns a new — derived — function that iterates differently. The core iterators are ' (each), / (over), \ (scan), and ': (each prior) — a few more (each-left \:, each-right /:, each-parallel peach, and case) are covered on the Iterators page:
+/ / + modified by over -> reduces a list: +/[1 2 3] = 6
+\ / + modified by scan -> running totals: +\[1 2 3] = 1 3 6
,' / , modified by each-both -> pairwise join: ,'[1 2;10 20] = (1 10;2 20)Derived Function
A derived function is the result of applying an iterator to a function — it isn't the iterator itself. The whole chain, from primitive to result, looks like this:
+ operator (primitive function)
│
│ / is the iterator — "modify + with over"
▼
+/ derived function
│
│ applied to data
▼
+/[1 2 3] -> 6 application/is the iterator.+/is the derived function produced by applying/to+.
A derived function is a normal function and can be applied like any other.
A derived function can even have a different rank from the function it's built from. + is binary (+[10;20] → 30), but +/ can be called as either unary or binary:
+/[1 2 3 4] / unary -> 10 (sum the list)
+/[100;1 2 3 4] / binary -> 110 (100 plus the sum of the list)This is common among derived functions, and is one reason they're often treated as functions in their own right rather than as a shorthand notation.
Advanced — syntax details: A derived function's calling syntax also depends on how many arguments you give it. +\ (scan) can be called unary or binary — and the binary form can be written with brackets or infix:
+\[1 2 3] / unary -> 1 3 6 (running totals)
+\[1; 1 2 3] / binary -> 2 4 7 (seed 1, then running totals)
1 +\ 1 2 3 / same as above, written infix -> 2 4 7Note what is missing from that list: +\ 1 2 3, written bare with nothing on its left, is an error. This reflects a general rule: a function derived by postfix iteration is always infix, regardless of its own rank. Written bare, it expects something to its left; with nothing there, +\ 1 2 3 fails to parse — and so does count' txt. Bracket notation always works (+\[1 2 3], count'[txt]), and wrapping the derived function in parentheses turns it into an ordinary value that can be applied prefix instead:
(+\) 1 2 3 / 1 3 6
(+\)[1; 1 2 3] / 2 4 7
txt:("the";"quick";"brown";"fox")
(count') txt / 3 5 5 3Projection
A projection is created by supplying only some of a function's arguments, leaving the rest as placeholders to be filled in later — similar to partial application in languages like Python or JavaScript:
f: {x+y+z}
g: f[10;;] / fix x:10, leave y and z open
g[20;30] / 60Projections are heavily used in functional qSQL and iteration.
Atomic, Uniform & Aggregate Functions
These describe how a function's result relates to the shape of its input:
- Atomic — applies itself to a list item-by-item automatically:
neg 1 2 3already returns-1 -2 -3, so wrapping it ineachchanges nothing. Formally, atomic is a special case of uniform wheref x ~ f' x— applyingfto a list gives the same result as applying it to each item individually. Most primitive operators (and functions likesignum) are atomic. The same idea applied to binary functions is called scalar extension: when one argument is an atom and the other is a list, the atom is automatically broadcast to match —1 2 3 + 10→11 12 13. - Uniform — preserves the top-level structure of its input. For example,
deltas 10 15 20 18returns10 5 5 -2— one result for each input item. Not all uniform functions are atomic —deltasdepends on consecutive items and can't be applied atom-by-atom. - Aggregate — reduces a list to a smaller result, often an atom:
sum,min,max,avg,count.
Function Application
q supports several ways to apply a function to its arguments:
| Style | Position | Example |
|---|---|---|
| Bracket | function, then arguments in [...] | {x+1}[2], +[1;2] |
| Prefix | unary function, then its argument — no brackets | neg 10, count 1 2 3 |
| Infix | binary operator, written between its two arguments | 1+2, 10 mod 3 |
| Postfix | iterator, written after the function it modifies | +/, count' |
Bracket form is the most general — every function can be applied this way, regardless of rank.
Prefix and infix describe where a function sits relative to its arguments — the data it operates on. Postfix is different: it describes where an iterator sits relative to the function it modifies, not relative to any data. In count', the Each iterator ' is postfix to count — together they form a derived function, which is then applied to data: count'[(1 2;3 4 5)] → 2 3. Only iterators can be applied postfix — for any other function, this isn't valid syntax.
(The keyword each gives the same result with friendlier syntax: count each (1 2;3 4 5). Here each is a binary keyword applied infix, with the function count as its left argument.)
Applicable Value
An applicable value is anything that can be applied to arguments or indexes — not just functions. Lists, dictionaries, and tables are applicable too, via the same [...] syntax — even file and process handles are applicable values, used for I/O and IPC:
count[1 2 3] / function applied to an argument -> 3
(10 20 30)[1] / list applied to an index -> 20
(`a`b!10 20)[`a] / dictionary applied to a key -> 10
t:([]a:1 2 3)
t[1] / table applied to a row index -> a| 2This is why "application" in the q documentation isn't limited to functions — the term applicable value covers any of these.
Application & Invocation
To apply a function means to evaluate it on its arguments. Application and invocation are used interchangeably in q — both simply mean "calling" a function. Bracket, prefix, and infix (see Function Application above) are just different notations for the same thing:
{x+y}[10;20] / bracket
sum 1 2 3 / prefix
1+2 / infixEach is simply an application of a function to its arguments — the syntax differs, but the meaning doesn't. The operators @ (Apply At) and . (Apply) let you write application explicitly, as a function in its own right, which is useful when the function to apply is itself held in a variable or passed as an argument.
Apply At (@)
Apply At applies a unary function to a single argument value — that value may itself be a list:
count @ 1 2 3 / same as count 1 2 3 -> 3
neg @ 10 / same as neg 10 -> -10@ has other forms too — e.g. Amend At uses it for indexing and in-place updates:
@[1 2 3; 1; :; 100] / set index 1 to 100 -> 1 100 3These indexing/amendment forms are covered in later sections — the point here is just that @ is more than a simple "call this function" operator.
Apply (.)
Apply applies a function to a list of arguments — useful once a function takes more than one:
{x+y} . (1;2) / 3
{x+y+z} . (1;2;3) / 6Composition (Trains)
When two or more values are written next to each other with no argument between them, q treats the whole sequence as a single function called a train, evaluated right to left — each value is applied to the result of the one on its right. neg sum is a 2-element train, and is q's standard way to write a composition. Applied straight to data, it just works:
neg sum 1 2 3 / sum 1 2 3 -> 6, then neg 6 -> -6But if you try to save the train under a name with no data attached, you'll hit a type error:
c: neg sum / type error — q tries to apply neg to the value `sum` itselfOne way to turn the train into a reusable function is to finish it with @ (for a unary chain). This tells q "this is a function waiting for an argument", not "apply neg to sum right now":
c: neg sum@
c 1 2 3 / -6
c (1 2;3 4) / -4 -6neg sum@ is shorthand for neg@sum@, with all but the last @ dropped — the same pattern extends to longer chains:
tc: til count@ / count and til are both unary
tc "abc" / count "abc" -> 3, then til 3 -> 0 1 2Advanced: if the last function in the chain is binary, use . instead of @:
di: reciprocal(%). / % is binary ("divide into")
di 2 3 / 2%3 -> 0.6667, then reciprocal -> 1.5Summary
Before tackling iterators, make sure these terms are familiar: function, primitive vs built from primitives, lambda (signed/unsigned), argument, rank (nullary/unary/binary/ternary/variadic), operator vs keyword, iterator, derived function, projection, atomic/uniform/aggregate, the four application styles (bracket/prefix/infix/postfix), applicable value, application/invocation, apply (@/.), and composition (trains).