How to Work with Functions

This page explains how to define, call, and manage functions in q, including arguments, scoping, projections, and return behavior.

A function in q is a reusable block of logic, a sequence of expressions that execute in order. Functions can take zero or more inputs and return an output.

Overview of steps

  1. Define a function

  2. Treat functions as data

  3. Understand function rank

  4. Call functions with arguments or projections

  5. Use anonymous functions

  6. Work with function arguments

  7. Manage local and global variables

  8. Pass variables by reference

  9. Return values and exit behavior

  10. Use projections for partial function application

1. Define a function

Define a function in q using lambda notation, which consists of:

  • A pair of curly braces {}

  • An optional argument list (up to 8 named parameters) inside square brackets []

  • One or more expressions separated by semicolons ;

For example, let's define a lambda named plus that adds two arguments:

q

Copy
q)plus:{[x;y] x + y}


In q, the term lambda refers to any function defined using this notation, whether it's anonymous or assigned to a name.

2. Treat functions as data

Functions in q behave like other data types such as integers or symbols. Use the type function to confirm a function’s type:

q

Copy
q)func:{[x;y]x+y}
q)type func
100h

A return value of 100h indicates a lambda function. You can:

  • Pass functions between processes via IPC

  • Use them as arguments or return values in other functions

  • Store them in collections like lists or dictionaries

Functions that operate on or return other functions are called higher-order functions.

3. Understand function rank

The rank (or valence) of a function refers to the number of arguments it accepts.

You may define functions with up to 8 arguments. Using more raises a params error:

q

Copy
q)f:{[a;b;c;d;e;f;g;h]a*b-c+d*e-f*g+h}
q)f:{[a;b;c;d;e;f;g;h;i]a*b-c+d*e-f*g+h+i}
'params
  [0]  f:{[a;b;c;d;e;f;g;h;i]a*b-c+d*e-f*g+h+i}
       ^

This limit does not restrict the amount of data passed; each argument may be a complex structure such as a list or dictionary.

Functions are often described by their rank:

  • Niladic: accepts no arguments (rank of 0)
  • Monadic/Unary:accepts one argument (rank of 1)
  • Dyadic/Binary: accepts two arguments (rank of 2)

Functions can inspect the type or length of their arguments at runtime using type or count.

This allows them to branch logic accordingly; for example, built-ins like load and hopen behave differently depending on input type.

4. Call functions with arguments or projections

Call a function in q using function application syntax: write the function name followed by arguments inside square brackets [], separated by semicolons ;:

q

Copy
q)func:{[x;y]x+y}
q)func[22;33]
55

Call functions without arguments

If the function doesn’t require arguments, include empty brackets when calling it:

q

Copy
q)func:{show "func called";}
q)func[]
"func called"

Passing extra arguments to such a function has no effect:

q

Copy
q)func:{show "func called";}
q)func[111]
"func called"

Evaluate expressions in arguments

q evaluates expressions inside argument positions before passing them:

q

Copy
q)func:{[x;y]x*y}
q)func[2+8;2]
20

Handle rank errors

Calling a function with too many arguments results in a rank error.

q

Copy
q)func:{[x;y]x*y}
q)func[22;33;231;123]
'rank             

Call functions by name

You can call a function directly using its variable name or indirectly by symbol:

q

Copy
q)func:{[x;y]x+y}
q)func[10;2]
12

q)`func[10;2]
12

q)a:`func
q)a[10;2]
12          

Use prefix notation

Functions that take only one argument also support prefix notation, omitting brackets:

q

Copy
q)f:{[x]x*x}
q)f[22]
484
q)f 22                  / prefix notation
484              

Calling a function with fewer arguments than declared results in a projection.

5. Use anonymous functions

Use anonymous functions when you want to define logic inline without assigning it to a named variable. Anonymous functions are useful for one-off operations or dynamic evaluation.

Define and call inline

Define an anonymous function using {} and call it immediately:

q

Copy
q){[x]x*x} 2
4      

Apply to a list

Use an anonymous function with each to apply logic to every item in a list. In the example below, we convert a list of server addresses into connection handles. The anonymous function first transforms each string into a symbolic handle using hsym, then opens a connection using hopen:

q

Copy
q)machines:("qa-machine1:1234";"qa-machine2:5234";"qa-machine3:2234")
q)h:{[x]hopen hsym `$x} each machines
6 7i
                    

Store functions in collections

Store anonymous functions in data structures like lists, dictionaries, or tables to support dynamic dispatch. This allows you to choose and execute a function at runtime based on context, rather than hardcoding function names.

6. Work with function arguments

Use different techniques to define and validate function arguments in q. This includes implicit argument names and optional type checking introduced in kdb+ 4.1 (2024.02.13).

Use implicit arguments

Define a function without naming its arguments. q automatically provides up to three implicit arguments:

  • x (first)

  • y (second)

  • z (third)

These names become available based on which are referenced in the function body.

q

Copy
q)f:{22+x+x}  / implicit single argument x
q)f[2]
26
q)f:{y-x}     / implicit single argument x and y
q)f[2;10]
8
q)f:{z*z}     / z used, but x and y are not used. implicit argument z, with x and y added even though not used
q)f[2;3;4]    
16                

Anonymous functions also benefit from implicit arguments:

q

Copy
q)h:{hopen hsym `$x} each ("qa-machine1:1234";"qa-machine2:5234")   / anonymous function with an implicit single argument x

A function with named arguments is called signed. Without named arguments, it is unsigned.

Apply argument type checking

As of kdb+ 4.1 (2024.02.13), define argument types inside the function signature using a single-character type code after a colon (:). For example, use `j to restrict a parameter to type long.

q

Copy
q)f:{[someLong:`j] 2*someLong}
q)f[2]
4
q)f[2.2]
'type
  [1]  f:{[someLong:`j] 2*someLong}          

This enforces type safety and improves code robustness. For more details, see the kdb+ 4.1 release notes.

7. Manage local and global variables

Use local and global variables to control scope and data visibility in q functions. Understand how variable assignment and access behave depending on the context.

Define local variables

Create local variables inside a function using :. Local variables:

  • Exist only during function execution

  • Remain invisible outside the function scope

  • Cannot be used in call-by-name functions

  • Stay hidden from local functions nested inside the same scope

Local assignments don't affect external values:

q

Copy
q)v:22
q)f:{[x]x:100}
q)f[v]
100
q)v
22               

Modifying elements of a passed-in vector also has no lasting effect:

q

Copy
q)v:1 2 3
q)f:{[x]x[0]:100}
q)f[v]
q)v
1 2 3          

Assignments with : apply locally and don't overwrite global variables:

q

Copy
q)a:22                         / global 'a'
q)f:{[x]a:33;b:44;a+b+x}       / function creates local variables 'a' and 'b', local 'a' takes precedence
q)f[1]
78
q)a                            / global 'a' remains unchanged
22
q)b                            / no global 'b' defined, error occurs
'b
  [0]  b
       ^

Resolve references to names not defined locally from the current namespace:

q

Copy
q)a:42           / assigned in root
q)f:{a+x}
q)f 1            / f reads a in root
43
q){a:1000;f x}1  / f reads a in root
43            

Avoid assigning locals conditionally - local variables initialize to empty list () and conditional paths may leave them undefined:

q

Copy
q)t:([]0 1)
q){select from t}[]                       / global t
x
-
0
1
q){if[x;t:([]`a`b)];select from t} 1b     / local t
x
-
a
b
q) {if[x;t:([]`a`b)];select from t} 0b     / local t is ()
'type
  [4]  {if[x;t:([]`a`b)];select from t}
                         ^             

Use global variables

Access

Resolve names not defined locally from the current namespace:

q

Copy
q)v:10
q)f:{[x]x+v}
q)f[2]
12                   

Resolution depends on the active namespace:

q

Copy
q)v:10
q)\d .foo
q.foo){[x]x+v}[2] / errors as .foo.v doesn't exist
'v
  [1]  {[x]x+v}
             ^
q.foo))\
q.foo)v:20
q.foo){[x]x+v}[2] / resolves to .foo.v
22
q.foo)\d .
q){[x]x+v}[2]     / resolves to v in top namespace
12             

Assign

Assign global values using ::. These assignments persist beyond the function call:

q

Copy
q)v:0
q)f:{[x]v::x;x+x}
q)f[1]
2
q)v
1
q)f[2]
4
q)v
2                

Avoid confusion when assigning to globals with the same name as locals. :: still binds to the local scope if already defined:

q

Copy
q)v:0
q)f:{[x]v:0;v::x;x+x}
q)f[1]
2
q)v
0        

Use set to reliably write to global variables:

q

Copy
q)v:0
q)f:{[x]v:0;`v set x;x+x}
q)f[1]
2
q)v
1                

Use get to access global variables by name:

q

Copy
q)x:22
q)f:{[x]show x;}           / prints local variable x
q)f 101
101
q)f:{[x]show get `x;}      / prints global variable x
q)f 101
22   

8. Pass variables by reference

Avoid copying large datasets by passing variable names to functions and modifying them using get and set.

By default, q passes arguments by value. When working with large vectors or tables, use symbolic references instead to access or update values efficiently.

q

Copy
q)a:10 20 30 40 50
q)f:{[x]show get x;x set 10 20 30;}
q)f[`a]                  / call function, passing variable name
10 20 30 40 50
q)a                      / function used set to change variable
10 20 30      

This method avoids unnecessary data copying and enables controlled updates from within functions.

9. Return values and exit behavior

Control what your function returns, whether it's a result, an early exit, or no value at all.

Return the result of the last expression

If the final expression does not end with a semicolon, the function returns its value:

q

Copy
q)f{[x]x+x}
q)f[2]
4                

Return early with an empty assignment

To return early (before the final expression), use an empty assignment (: followed by a value):

q

Copy
q)c:0
q)f:{a:6;b:7;:a*b;c::98}
q)f 0
42
q)c
0             

Create a void function

Create a void function

Use a semicolon on the last line to suppress the return value. The function returns the generic null.

q

Copy
q)f:{2*x;}      / last statement is empty
q)f 10          / no result shown
q)(::)~f 10     / matches generic null
1b         

Signal an error or abort

To abort evaluation immediately, use signal, which is ' with a value to its right.

q

Copy
q)c:0
q)g:{a:6;b:7;'`TheEnd;c::98}
q)g 0
{a:6;b:7;'`TheEnd;c::98}
'TheEnd
q)c
0         

Example: Check argument type before proceeding. Use early return or error signaling to validate input:

q

Copy
q)f:{if[7h<>type x;'"type"]count x}
q)f[33 22]
2
q)f[22.4]
'type
  [0]  f[22.4]
       ^                  

10. Use projections

When you call a function with fewer arguments than its defined rank (i.e. the number of required parameters), q returns a projection - a partially applied function. This projection “locks in” the arguments you’ve supplied and waits for the rest. The rank of the resulting projection is the original rank minus the number of arguments provided.

Other languages may refer to this concept as currying.

Create a projection by omitting arguments

Call a function with fewer arguments than it requires to return a projection (a partially applied function):

q

Copy
q)add:{[x;y]x+y}
q)add42:add[42;]           / create a projection with the first parameter value fixed to '42'
q)add42[2]                 / execute the original function with parameters 42 and 2
44
q)add42[4]                 / execute the original function with parameters 42 and 4
46        

Create projections in stages

Chain projections by supplying arguments over multiple stages:

q

Copy
q)addm:{[x;y;z]x+y+z}    
q)addm[2;;3][6]            / projection with 1st and last parameter, then executed providing the remaining 2nd paramter
11
q)addm[2;;][2;][6]         / projection with the 1st parameter (2nd/3rd remaining), then create a new projection with only the first of the remaining 2 parameters needed, then execute the function when last parameter provided 
10              

Preserve logic in projections

The function logic is frozen at the time you create the projection. Redefining the original function later does not affect previously created projections:

q

Copy
q)f:{x*y}
q)g:f[3;]   / triple
q)g 5
15
q)f:{x%y}
q)g 5       / still triple
15           

Use full-length argument lists

Use placeholders (;) for omitted arguments to clearly show the projection:

q

Copy
q)foo:{x+y+z}
q)goo:foo[2]    / discouraged
q)goo:foo[2;;]  / recommended             

Check the type of projections

As with functions, projections have their own data type. Use type to inspect it:

q

Copy
q)f:{[x;y]x+y}
q)type f
100h
q)type f[1;]
104h            

Projections let you fix arguments and reuse or defer execution until more input is provided. Use them to simplify function reuse and construct dynamic logic flows.