# QforMortals2/functions

## Contents |

# Functions

## Overview

In this chapter, we cover functions in depth. Before starting, you may wish to review the Mathematical Functions Refresher if it has been a while since your last encounter with mathematical functions.

Appendix A contains specifics and examples of all the q built-in functions. We shall use built-in functions in the following sections without introduction. Simply look it up in Appendix A.

## Function Specification

The notion of a function in q corresponds to a (mathematical) map that is specified by an algorithm. A *function* is a sequence of expressions to be evaluated, having optional input parameters and a return value. *Application* of a function is the process of evaluating the expressions in sequence, substituting actual arguments for any formal parameters. If a return value is specified, the function evaluates to its return value.

: Because a q function can access global variables, the corresponding mathematical mapping actually includes the workspace as an implicit parameter. In other words, q is not a pure functional language because functions can have side effects.Advanced

### Function Definition

The distinguishing characteristic of function definition is a matching pair of braces `{` and `}` enclosing a sequence of expressions separated by semi-colons. In contrast to verbose languages, a function's input parameters and the return value are not typed. In fact, they don't even need to be declared explicitly. Even the function name is optional.

Following is a full specification of a function that returns the square of its input. Observe that we have added optional whitespace after the parameter for readability.

f:{[x] x*x}

You call `f` by enclosing its actual parameter in square brackets,

f[3] 9

Here is a compact form of an equivalent function evaluation in which optional aspects are omitted,

{x*x}[5] 25

### Function Notation and Terminology

The notation for function definition is,

- {[
*p*]_{1};...;p_{n}*e*}_{1}; ...; e_{n}

- {[

where the optional *p _{1}, ... , p_{n}* are formal parameters and

*e*is a sequence of expressions to be evaluated in left-to-right sequence.

_{1}, ... , e_{n}For readability, we shall normally insert optional whitespace after the closing square bracket that closes the parameter list, as well as after each semicolon separator. Other styles may differ.

The reason the expressions in a function are evaluated in left-to-right sequence is so that the sequence becomes top-to-bottom when the function definition is split across multiple lines. Specifically, right-to-left expression evaluation would result in the following definition,Note:

f:{[p1;...;pn] e,,1,,; ...; e,,n,,}

being evaluated from bottom to top, which would be very unnatural.

The number of formal input parameters, either implicit or explicit, is the function's *valence". Most common are monadic (valence 1) and dyadic (valence 2). You specify a function with no parameters (*niladic*) with an empty argument list,*

{[] ...}

The maximum valence currently permitted is 8, so specifying more than eight arguments will cause an error. You can circumvent this restriction by encapsulating multiple parameters in a list argument.Important:

Q functions should be compact and modular: each function should perform well-defined unit of work. Due to the power of q operators and built-in functions, helper functions are often one liners. When a function exceeds 20 expressions, you should ask yourself if it can be factored.Recommendation:

Variables that are defined within the expression(s) of a function are called *local* variables.

The "return value" of a function is the value carried by the function evaluation. It is determined by the following rules:

- If an empty assignment appears - i.e., a ':' with no variable name to the left - then its assignment value is returned.

- Otherwise, if any local variables are assigned, the assigned value of the last one is returned.

- Otherwise, the result of the last expression evaluation is result.

For example, the following function specifications result in the same input-output mapping.

f1:{[x] :x*x} / explicit return f2:{[x] r:x*x} / local variable is returned f3:{[x] x*x} / last expression is result

So does this one, even though it includes useless and unexecuted evaluations.

f4:{[x] a:1;:x*x;3}

: In contrast to k, the q operators are not overloaded on valence, meaning that an operation does not have different functionality for different numbers of arguments. However, q some operators (and build-in functions) are overloaded on the types of the arguments, or even the sign of the arguments. For example, to understand the exact use of (?), you must carefully examine the operands.Advanced

### Implicit Parameters

If you omit the formal parameters and their brackets, three implicit positional parameters `x`, `y` and `z` are automatically available in the function's expressions. Thus, the following two specifications are equivalent:

f:{[x] x*x} g:{x*x}

And so are,

f:{[x;y] x+y} g:{x+y}

When using implicit parameters, `x` is always the first actual argument, `y` second and `z` third. The following function `g ` generates an error unless it is called with three parameters.

g:{x+z} / likely meant x+y; requires 3 parms in call g[1;2] / error...needs three parameters {z+z}[1;2] g[1;2;3] / OK...2nd value is required but ignored 4

: If you use the names x, y and z in a function, reserve them for the first three parameters, either explicit or implicit. Any other use will almost certainly lead to confusion, if not to trouble.Recommendation

### Anonymous Functions

A function can be defined without being assigned to a variable. Such a function is called *anonymous* since it cannot be evaluated by name.

{x+y}[4;5] 9

An anonymous function can be appropriate when it will be evaluated in only one location. A prevalent use is in-line helper functions within other functions.

f{[...] ...; {...}[...]; ...}

It is arguably more readable to extract anonymous functions.

g:{...} f:{...; g[...]; ....}

This is a matter of coding style.

### The Identity Function (::)

The identity function `::` returns its argument. It is useful for specifying defaults when using functional forms of `amend` and `select`.

: The identity function cannot be used with juxtaposition.Important

::[`a] `a ::[1 2 3] 1 2 3 :: 42 '

### Functions are Nouns

The q entities we have met until now have been either nouns or verbs. Atoms and lists are nouns. Operators are verbs. In the following expression,

a:1+L:100 200 300

`a`, `L` and the literals 100, 200, 300 are nouns, while the assign and plus operators are verbs.

It may come as a surprise that functions are also nouns. We can write,

a:3 f:{[x] 2*x} a:f a 3 6

Operators used as functions are also nouns, so continuing the previous example we can also write,

L:(f;+) L {2*x} +

: The display ofNoteLillustrates that a function name is resolved to its body at the time of assignment. If the definition offis subsequently modified,Lwillnotchange.

## Local and Global Variables

### Local Variables

A variable that is defined by assignment in an expression in a function is called a *local* variable. For example, `a` is a local variable in the following function.

f:{a:42; a+x}

A local variable exists only from the time it is first assigned until the completion of the enclosing function's evaluation; it has no value until it is actually assigned. Provided there is no variable `a` already assigned in the workspace, evaluation of the function does not create such a variable. Using f as above,

f[6] 48 a `a

### Global Variables

Variables that have been assigned outside any function definition are called *global* variables.

b:6 f:{x*b} f[7] 42

To assign a global variable inside a function, use a double colon ( `::` ), which tells the interpreter not to create a local variable with the same name.

b:6 f:{b::7; x*b} f[6] 42 b 7

### Local and Global Collision

When a local variable is defined with the same name as a global variable, the global variable is obscured.

a:42 f:{a:98; x+a} f[6] 104 a 42

: When local and global names collide, the global variable is always obscured. Even double colon assignment affects the local variable. For example,Important

a:42 f:{a:6;a::98; x*a} f[6] 588 a 42

## Amend (:)

### Amend in C Language

We have already seen the basic form of assignment using amend

a:42

Programmers from languages with C heritage will be familiar with expressions such as,

x += 2; // C expression representing amend

which is shorthand for,

x = x + 2; // C expression

This is usually read simply "add 2 to x" but more precisely is, "assign to x the result of adding 2 to the current value of x." This motivates the interpretation of such an operation as "amend," in which `x` is re-assigned the value obtained by applying the operation `+` to the operands `x` and `2`. By implication, a variable can only be amended if it has been previously assigned.

### Simple Amend

In q, the equivalent to the above C expression uses `+:` as the operator.

x:42 x+:2 x 44

There is nothing special about `+` in the above discussion. Amend is available with any binary verb, as long as the operand types are compatible.

a:42 a-:1 a 41

We shall see interesting examples of amend with other operators in later chapters.

### Amend with Lists

This capability to amend in one step extends to lists and indexing,

L1:100 200 300 400 L1[1]+:9 L1 100 209 300 400 L1[0 2]+:99 L1 199 209 399 400 L1:100 200 300 400 L1[0 1 2]+:1 2 3 L1 101 202 303 400 L2:(1 2 3; 10 20 30) L2[;1]+:9 L2 1 11 3 10 29 30 L2:(1 2 3; 10 20 30) L2[0;1]+:100 L2 1 102 3 10 20 30

: Amend enforces strict type matching with simple lists, since the result must be placed back into the list,Note

L1[0]+:42f `type

## Projection

### Function Projection

Sometimes a function of valence two or more is evaluated repeatedly while some of its arguments are held constant. For this situation, a multivalent function can have one or more arguments fixed and the result is a function of lower valence called the *projection* of the original function onto the fixed arguments. Notationally, a projection appears as a function call with the fixed arguments in place and nothing in the other positions.

For example, the dyadic function which returns the difference of its arguments,

diff:{[x;y] x-y}

can be projected onto the first argument by setting it to 42, written as,

diff[42;]

The projected function is the monadic function "subtract from 42",

diff[42;][6] 36

This projection is equivalent to,

g:{[x] 42-x} g[6] 36

We can also project `diff` onto its second argument to get "subtract 42",

diff[;42][6] -36

which is equivalent to,

h{[x] x-42}

When a function is projected onto any argument other than the last, the trailing semi-colons can be omitted. Given `diff` as above,

diff[42][6] 36

: It will make your intent more evident if you doRecommendationnotomit trailing semi-colons when projecting. For example, withdiffas above, a reader will immediately recognize the projection,

diff[42;][6] / instead of diff[42][6]

The brackets denoting a function projection are required, but the additional brackets in the projection's evaluation can be omitted with juxtaposition (as for any regular function).

diff[;42] 6 -36 diff[42] 6 36

Which notation to use is a matter of coding style.

### Verb Projection

A binary verb can also be projected onto its left argument, although the notation may take some getting used to. For example, the projection of - onto its left argument is,

(42-)6 36

A verb cannot be projected onto its right argument, since this would lead to notational ambiguity. For example, `(-42)` is the atom `-42` and not a projection.

(-42) -42

If you really want to project onto the right argument of an operator, you can do so by using the dyadic function form and juxtaposition of the argument.

-[;42] 98 56

In fact, the whitespace is not necessary in this example.

-[;42]98 56

We warned you about the notation.

### Multiple Projections

When the original function has valence greater than two, it is possible to project onto multiple arguments simultaneously. For example, given,

f:{x+y+z}

we can project `f` into its first and third arguments and end up with a monadic function,

f[1;;3][5] 9

We arrive at the same result by taking the projection `f[1;;]` - now a dyadic function - and projecting onto its second argument to arrive at `f[1;;][;3]`.

f[1;;][;3][5] 9

This is equivalent to projecting in the reverse order,

f[;;3][1;][5] 9

: IfNotegis defined as a projection offand the definition offis changed,gremains the projection of the originalf.

f:{[x;y] x-y} g:f[42;] g {[x;y] x-y}[42;] g[6] 36 f:{[x;y] x+y} g[6] 36

This can be seen by displaying `g` on the console,

g {[x;y] x-y}[42;]

## Lists and Functions as Maps

This section explores the deeper relationship between lists and functions. While it can be skipped on first reading by the mathematically faint of heart, that would be like not eating your vegetables when you were a kid.

### Similarity of Notation

You have no doubt noticed that the notation for list indexing is identical to that for function evaluation. That is,

L:(0 1 4 9 16 25 36) f:{[x] x*x} L[2] 4 f[2] 4 L 5 25 f 5 25 L 3 6 9 36 f 3 6 9 36

This is not an accident. In Creating Typed Empty Lists we saw that a list is a map defined by means of the implicit input-output correspondence given by item indexing. A function is a map defined by a sequence of expressions representing the algorithm used to obtain an output value from the input parameters. For consistency, the two different mechanisms for implementing a map do have the same notation. It may take a little time to get accustomed to the rationality of q.

### Item-wise Extension of Atomic Functions

With the interpretation of lists and functions as maps, we can motivate the behavior of list indexing and function application when a simple index or atomic parameter is replaced by a simple list of the same. Specifically, we are referring to,

L[2 5] 4 25 f[2 5] 4 25

in the previous examples. The expression enclosed in brackets is a simple list, call it `l`. Viewing the list `I` as a map, the two expressions are the composition of `L` and `I`, and the composition of `f` and `I`,

L[2 5] is (L[2]; L[5]) f[2 5] is (f[2]; f[5])

For a general list `L`, function `f` and item index list `I`, the compositions are,

L ◦ I(j) = L(i,,j,,) f ◦ I(j) = f(i,,j,,)

### Indexing at Depth and Ragged Arrays

Next, we show the deeper correspondence between list indexing and multivalent function evaluation. Notationally, a nested list is a list of lists, but it can also be viewed functionally as a compact form of the input-output relationship for a multivariate map. This mapping transforms tuples of integers onto the constituent atoms of the list and has valence equal to one plus the level of nesting of the list.

For example, a list with no nesting is a monadic map of integers to its atoms via item indexing.

L1:(1;2h;`three;"4") L1[3] "4"

A list with one level of nesting can be viewed as an irregular (or ragged) array by laying its rows out one above another. For example, the list `L2` specified as,

L2:((1b;2j;3.0);(4.0e;`five);("6";7;0x08;2000.01.10))

can be thought of as a ragged array. The console display does just this,

L2 (1b;2j;3f) (4e;`five) ("6";7;0x08;2000.01.10)

This representation of a ragged array is a generalization of the I/O table for monadic maps. From this perspective, indexing at depth is a function whose output value is obtained by indexing into the ragged array via position. In other words, the output value L2[i;j] is the *j ^{th}* element of the

*i*row,

^{th}L2[1;0] 4.0e

This motivates the interpretation of `L2` as dyadic map over a sub-domain of the two-dimensional Cartesian product of non-negative integers and with range equal to the atoms of `L2`. The duple `i,j` is mapped positionally, analogous to simple item indexing.

: It is possible create a ragged array of any number of columns using 0N as the number of rows with the reshape operator (Advanced#).

0N 3#til 10 0 1 2 3 4 5 6 7 8 ,9

### Projection and Index Elision

You may have also noticed that the notations of function projection and elided indices in a list are identical. Revisiting the example of elided indices we used in Nesting,

#!q L :((1 2 3;4 5 6 7);(`a`b`c`d;`z`y`x`;`0`1`2);("now";"is";"the"))

Define the list `L1` by eliding the first and last index as,

L1:L[;1;] L1 4 5 6 7 `z`y`x` "is"

Viewing `L` as a map of valence three whose output value is obtained by indexing at depth, this makes `L1` the projection of `L` onto its second argument. From this perspective, `L1` is a dyadic map that retrieves values from a sub-list,

L1[1;2] `x

### Out of Bounds Index

The previous discussion also motivates the explanation for the behavior of item indexing in case an "out of bounds" index is presented. In verbose languages, this would either result in some sort of error - the infamous indexing off the end of an array in C‚ - or an exception in Java and C#.

By viewing a list as a function defined on a sub-domain of integers, it is reasonable to extend the domain of the function to all integers by assigning a null output value to any input not in the original domain. In this context, null should be thought of as "missing value." This is exactly what happens.

In the following examples, observe that the type of null returned matches the item type for simple lists and is `0N` for a general list

L1:1 2 3 L1[-1] 0N L2:100.1 200.2 300.3 400.4 L2[100] 0n L3:"abcde" L3[-1] " " L4:1001101b L4[7] 0b L5:(1;`two;3.0e) L5[5] 0N

## Creating Strings from Data

As mentioned earlier, q strings are simple lists of char, which play a role similar to strings in verbose languages. It is possible to convert data into strings, akin to the toString() method in O-O languages.

The function `string` can be applied to any q entity to produce a textual representation suitable for display or use in external contexts such as text editors, Excel, etc. In particular, the `string` result does not contain any q formatting information. Also, note that the result of `string` is always a list of char. Following are some examples.

string 42 "42" string 6*7 "42" string 42422424242j "42422424242" string `Zaphod "Zaphod"

See Appendix A for more details on `string`.

## Adverbs

Syntactically q has nouns, verbs and adverbs. Data entities such as atoms, lists, dictionaries and tables are nouns. Functions are also nouns. Primitive symbol operators and operations expressed in infix notation are verbs. For example, in the expression,

c:a+b

`a`, `b` and `c` are nouns, while `:` and `+` are verbs. On the other hand, in

c:+[a;b]

`a`, `b`, `c` and `+` are nouns, while `:` is a verb.

An *adverb* is an entity that modifies a verb or function to produce a new verb or function whose behavior is derived from the original.

The following adverbs are available in q.

Symbol | Name |

' | each both |

each | each monadic |

/: | each right |

\: | each left |

/ | over |

\ | scan |

': | each previous |

: The character that represents each is the single quote (Note') which is distinct from the back-tick (`) used with symbols.

### each-both (')

Loosely speaking, the adverb each-both (') modifies a verb or function by applying its behavior item-wise to corresponding list elements. This concept is similar to the manner in which an atomic verb or function is extended to lists.

: There cannot be any whitespace betweenImportant'and the verb it modifies.

Perhaps the most common example of each is join-each ( `,'` ) which concatenates two lists item-wise. In its base form, join takes two lists and returns the result of the second appended to the first.

L1:1 2 3 4 L2: 5 6 L1,L2 1 2 3 4 5 6

Two lists of the same count can be joined item-wise to form pairs.

L3:100 200 300 400 L1,'L3 1 100 2 200 3 300 4 400

As in the case of item-wise extension of atomic functions, the two arguments must be of the same length, or either can be an atom.

L1,'1000 1 1000 2 1000 3 1000 4 1000 `One,'L1 `One 1 `One 2 `One 3 `One 4 "a" ,' "z" "az"

When both arguments of a derived function are atoms, the adverb has no effect.

3,'4 3 4

: A useful example of join-each arises when both arguments are tables. Since a table is a list of records, it is possible to apply join-each to tables with the same count. The item-wise join of records results in a sideways join of the tables.Advanced

t1:([] c1:1 2 3) t2:([] c2:`a`b`c) t1 c1 __ 1 2 3 t2 c2 __ a b c t1,'t2 c1 c2 ------- 1 a 2 b 3 c

### Monadic each

There is a form of each that applies to monadic functions and unary operators. It applies a (non-atomic) function to each element of a list. Monadic each can be notated in two equivalent ways for a monadic function `f`,

f each each[f]

The latter form underscores the fact that `each` transforms a function into a new function.

reverse each (1 2;`a`b`c;"xyz") 2 1 `c`b`a "zyx" each[reverse] (1 2;`a`b`c;"xyz") 2 1 `c`b`a "zyx"

The transform is arguably more readable when the base operation is a projection.

(1#) each 1001 1002 1004 1003 1001 1002 1004 1003 each[1#] 1001 1002 1004 1003 1001 1002 1004 1003

Observe that the result of the last example can also be obtained with `enlist`.

enlist each 1001 1002 1004 1003 1001 1002 1004 1003 flip enlist 1001 1002 1004 1003 1001 1002 1004 1003

The last expression executes fastest for long lists.

### each-left (\:)

The each-left adverb `\:` modifies the base function so that it applies the entire second argument to each item of the first argument.

: There cannot be any whitespace betweenImportant\:and the verb it modifies.

To append a given string to every string in a list,

("Now";"is";"the";"time") ,\: ", " "Now, " "is, " "the, " "time, "

### each-right (/:)

The each-right adverb `/:` modifies the base function so that it applies the entire first argument to each item of the second argument.

: There cannot be any whitespace betweenImportant/:and the verb it modifies.

To prepend a given string to every string in a list,

" ," ,/: ("Now";"is";"the";"time") " ,Now" " ,is" " ,the" " ,time"

### Cartesian Product (,/:\:)

To achieve a Cartesian (cross) product of two lists, begin with join-right `,/:` and modify it with each-left. The net effect is to join every item of the first argument with every element of the second argument.

L1:1 2 L2:`a`b`c L1,/:\:L2 1 `a 1 `b 1 `c 2 `a 2 `b 2 `c

There is an extra level of nesting that can be eliminated with `raze`.

raze L1,/:\:L2 1 `a 1 `b 1 `c 2 `a 2 `b 2 `c

You can also begin with join-left `,\:` and modify it with each-right.

raze L1,\:/:L2 1 `a 2 `a 1 `b 2 `b 1 `c 2 `c

Observe that the orders of the resulting items for `,/:\:` and for `,\:/:` are transposed.

: Cartesian product is also encapsulated in the functionNotecross.

L1 cross L2 1 `a 1 `b 1 `c 2 `a 2 `b 2 `c

### Over (/)

The over adverb `/` modifies a base dyadic function so that the items of the second argument are applied iteratively to the first argument.

* Important*: There cannot be any whitespace between

`/`and the function it modifies.

To add multiple items to another entity,

L:100 200 300 ((L+1)+2)+3 106 206 306 L+/1 2 3 106 206 306 0+/10 20 30 / easy way to add a list 60

To raze a list,

L1:(1; 2 3; (4 5; 6)) (),/L1 1 2 3 4 5 6

To use your own function,

f:{2*x+y} 100 f/ 1 2 3 822

: To delete multiple items from a dictionary,Advanced

d:1 2 3!`a`b`c d _/1 3 2| b

### Scan (\)

The scan adverb `\` modifies a base dyadic function so that the items of the right operand are applied cumulatively to the left operand.

: There cannot be any whitespace betweenImportant\and the function it modifies.

To find running sums,

100+\1 2 3 101 103 106 0+\10 20 30 / easy way to find running sums of list 10 30 60

To use your own function,

f:{2*x+y} 100 f\ 1 2 3 202 408 822

### each-previous (':)

The each-previous adverb `':` modifies a base dyadic function so that each item of the right operand is applied to its predecessor. The left operand of the adverb is taken as the predecessor for the initial item.

: There cannot be any whitespace between ': and the function it modifies.Important

To find the running 2-item sum with 0 before the initial item,

0+':1 2 3 4 5 1 3 5 7 9

More interesting is to determine the positions where items increase in value.

0w>':8 9 7 8 6 7 010101b -0w>':8 9 7 8 6 7 110101b

The left operand controls the initial result. The first expression results in initial 0b for all numeric lists, while the second results in initial 1b. Why?

## Verb Forms of Indexing and Evaluation

We are familiar with the syntactic forms of indexing and function application using either square brackets or juxtaposition.

L:(1 2;3 4 5; 6) L[0] 1 2 L[0 2] 1 2 6 L 0 2 1 2 6 L[1;2] 5 f:{x*x} f[0] 0 f[0 2] 0 4 f 0 2 0 4 g:{x+y} g[1;2] 3

There are equivalent verb forms for indexing and function application. The verb forms are read "index" or "apply" depending on the context.

### Verb @

The verb `@` takes a list or a unary function as its left operand and a list of indices or a list of arguments as its right operand. For a list operand, `@` returns the items specified by the right operand - i.e., indexing at the top level. For a function operand, `@` returns the result of applying the function to the arguments item-wise.

With `L` and `f` as above,

L@0 1 2 L@0 2 1 2 6 f@0 0 f@0 4 0 16

The evaluation of a niladic function with `@` requires an arbitrary scalar argument.

fn:{6*7} fn[] 42 fn@0N 42

: The verbAdvanced@also applies to dictionaries, tables and keyed tables. For dictionaries and keyed tables it performs lookup. Since a table is a list of records, it indexes records.

d:`a`b`c!10 20 30 d@`b 20 t:([]c1:1 2 3; c2:`a`b`c) t@1 c1| 2 c2| b kt:([k:`a`b`c]f:1.1 2.2 3.3) kt@`c f| 3.3

### Verb Dot (.)

The verb `.` takes a list or a multivalent function as its left operand and a list of indices or a list of arguments as its right operand. For a list left operand, verb `.` returns the result of indexing the list at depth as specified by the right operand. For a function left operand, verb `.` returns the result of applying the function to the arguments.

: VerbImportant.must be separated from its operands by whitespace if they are names or literal constants.

With `L` and `g` as above,

L . 1 2 5 g . 1 2 3

The verb . evaluates functions of any valence. This is useful when the function or arguments are supplied programmatically and the valence cannot be known beforehand.

: The right argument ofNote.must be a list.

f . 4 'type f . enlist 4 16

Use the null item `::` to elide an index when using verb `.` to index at depth.

m:(1 2 3;4 5 6) m[;1] 2 5 m . (::;1) 2 5

Evaluating a niladic function with . requires a singleton operand, which is arbitrary.

fn:{6*7} fn[] 42 fn . enlist 0N 42

: VerbAdvanced.provides a generalization of indexing at depth for complex entities comprised of general lists, dictionaries, tables and keyed tables. Perhaps the easiest way to understand its action is to view all such entities as composite mappings. Verb.evaluates the composite map by iteratively applying indexing/lookup on each item of the right operand to the result of the previous step.

The use of verb `.` in the first following complex is list indexing in all positions; in the second, the middle item is a lookup.

L1:(1;2 3;(4; 5 6)) L1 . 2 1 1 6 L2:(1;2 3;`a`b!(4;5 6)) L2 . (2;`b;1) 6

In the following complex dictionary, the first use of verb `.` yields lookup followed by indexing, whereas the second use is two lookups.

dd:`a`b`c!(1 2;1.1 2.2 3.3;`aa`bb!10 20) dd . (`a;1) 2 dd . (`c`bb) 20

Because a table is a list of records, verb `.` indexes a record on the first item and then performs a field lookup on the second.

t:([]c1:1 2 3;c2:`a`b`c) t . (1;`c2) `b

Because a keyed table is a dictionary mapping between two tables, verb `.` performs key lookup on the first item and then a field lookup on the second.

kt:([k:`a`b`c]f:1.1 2.2 3.3) kt . `b`f 2.2

## Functional Forms of Amend

The functions `@` and `.` can be used with valence three or four to apply any function to an indexed sublist and an optional second argument. The fact that the list can be a table that may be stored on disk makes this very powerful.

### Apply (@) for Dyadic Functions

The general form of functional `@` for dyadic functions is,

@[L;I;f;y]

While the notation is suggestive of lists, in fact `L` can be any mapping with explicit domain such as a list, dictionary, table, keyed table or open handle to a table on disk. Then `I` is a list of items in the domain of the map, `f` is a dyadic function and `y` is an atom or list conforming to `I`. When `L` is a list, the result is the item-wise application to the items of `L`, __indexed at the top level__ by `I`, of `f` and the parameter `y`. Over the subdomain `I`, the map output becomes,

L[I] f y / written as binary verb f[L[I];y] / written as dyadic function

Or, using verb @ for indexing,

(L@I) f y / written as binary verb f[L@I;y] / written as dyadic function

For example, to add 42 to certain items in a list,

L:100 200 300 400 I:1 2 @[L;I;+;42 43] 100 242 343 400

To replace these items,

@[L;I;:;42 43] 100 42 43 400

Observe that the argument `L` is unchanged,

L 100 200 300 400

In order to change the list argument, it must be referenced by name.

@[`L;I;:;42] / update L `L L 100 42 42 400

: The result of functional amend with a reference by name is a symbol containing the name of the entity affected, not to be confused with an error message.Note

: As mentioned previously,AdvancedLcan be a dictionary, a table, or even an open handle to a table on disk. In the general case, the resultf[L@I;y]is applied along the subdomain.

d:`a`b`c!10 20 30 @[d;`a`c;+;9] a| 19 b| 20 c| 39 t:([] c1:`a`b`c; c2:10 20 30) @[t;0;:;(`aa;100)] c1 c2 ------ aa 100 b 20 c 30

### Apply (@) for Monadic Functions

The general form of functional `@` for a monadic function is,

@[L;I;f]

Again the notation is suggestive of lists, but `L` is any map with explicit domain, `I` is a list of items in the domain of `L`, and f is a monadic function. When `L` is a list, the result is the item-wise application of f to the items of `L` indexed at the top level by `I`. Over the subdomain `I`, the map output becomes,

f L[I] / written as unary verb f[L[I]] / written as mondaic function

Or, using the verb form of @,

f[L@I]

For example,

L:101 102 103 I:0 2 @[L;I;neg] -101 102 -103

: In the general case, the resultAdvancedf[L@I]is applied along the subdomain.

d:`a`b`c!10 20 30 @[d;`a`c;neg] a| -10 b| 20 c| -30

### Dot (.) for Dyadic Functions

The general form of functional `.` for dyadic functions is,

.[L;I;f;y]

Again the notation is suggestive of lists, but `L` is a mapping with explicit domain, `I` is a list in the domain of `L`, `f` is a dyadic function and `y` is an atom or list of the proper shape. For a list, the result is the item-wise application to the items of `L` __indexed at depth__ by `I`, of `f` and the parameter `y`. Over the subdomain `I`, the map output becomes,

(L . I) f y / binary operator f[L . I;y] / dyadic function

For example, to add along a sublist,

L:(100 200;300 400 500) I1:1 2 I2:(1;0 2) .[L;I1;+;42] 100 200 300 400 542 .[L;I2;+;42 43] 100 200 342 400 543

To replace the same item,

.[L;I2;:;42 43] 100 200 42 400 43

Observe that the argument `L` is not modified.

L 100 200 300 400 500

In order to change L, it must be referenced by name.

L:(100 200;300 400 500) .[`L;I1;:;42] / update L `L L 100 200 300 400 42

: The result of functional amend with a reference by name is the name of the entity affected, not an error message.Note

: In the general case, the result f[L . I;y] is applied along the subdomain.Advanced

d:`a`b`c!(100 200;300 400 500;600) .[d;(`b;1);+;42] a| 100 200 b| 300 442 500 c| 600

### 4.9.4 Dot (.) for Monadic Functions

The general form of functional `.` for a monadic function is,

.[L;I;f]

Again the notation is suggestive of lists, but `L` is any map with explicit domain, `I` is a list in the domain of `L`, and `f` is a monadic function. For a list, the result is the item-wise application of `f` to the items of `L` indexed at the depth level by `I`. Over the subdomain `I`, the map output becomes,

f[L . I]

For example,

L:(100 200;300 400 500) I:1 2 .[L;I;neg] 100 200 300 400 -500

: In the general case, the result f[L . I] is applied along the subdomain.Advanced

d:`a`b`c!(100 200;300 400 500;600) .[d;(`b;1 2);neg] a| 100 200 b| 300 -400 -500 c| 600

Prev: Primitive Operations Next: Casting and Enumerations

©2006-2007 Kx Systems, Inc. and Continuux LLC. All rights reserved.