KDB文档 - Functions (Part 1)

311 阅读6分钟

Function Specification

A function is a sequence of expressions to be evaluated, having optional input parameters and a return value.

Function Definition

The function simply returns the value of the (last) expression evaluated. 

q){[x] x*x}[3]
9
q)f:{[x] x*x}
q)f[3]
9

Function Notation and Terminology

The formal notation for function definition is,

{[p1;...;pn] e1; ...; em}

The semi-colons in the body are separators, not terminators.  

q)a:2*3;6*7
42
q)a
6

The number of formal input parameters (implicit or explicit) is the function valence. Most common are unary (valence 1) and binary (valence 2). 

 A nullary function in q is a function that has no meaningful input. This is similar to a function taking void in C. In functional programming this is represented as a function defined on a type called "unit" having a single value, often written (). In q it is written with an empty parameter declaration,

f:{[] … }

q){[] 42} / pure function returns constant 42
_

The maximum valence permitted as of this writing (Sep 2015) is 8; specifying more than eight parameters will cause an error. You can circumvent this restriction by encapsulating multiple parameters in a list or dictionary.

This convention can be supplanted by using a unary overload of : that immediately terminates function evaluation and returns the value of the expression to its right. This style is discouraged.

q){[x] :x*x} / unnecessary use of :
q){[x] a:1; :x*x; b:3} / dead code

Function Application

q){[x;y] x+y}[3;4]
7
q)g:{[x;y] x+y}
q)g[3;4]
7

Function application in q is strict, meaning that expressions in arguments are evaluated before substitution is performed.

q)f:{[x] x*x}
q)f[0N!3+1]
4
16

The valence of a function is also called its rank. An application with too many arguments generates a 'rank error.

q) {[x] x*x}[3;4]
'rank

Functions with No Return Value

For example, it may send off a message asynchronously without waiting for an acknowledgement of receipt or it may update a global table.

q)fvoid:{[x] `a set x;}
q)fvoid 42
q)`a

In fact, the actual return value is the nil item :: that is a stand-in for void in this situation. Its display is suppressed in the q console but it can be revealed.

 q).Q.s1 fvoid 42
"::"

Application of a Name

q)f:{x*x}
q)f[5]
25
q).my.name.space.f:{2*x}
q)`.my.name.space.f[5]
10
q)g:{x+z}  
q)g[1;2;3] / 2nd arg is required but ignored
4

Anonymous Functions and Lambda Expressions

A function without a name is then called an anonymous function.

q)powers:({1}; {x}; {x*x}; {x*x*x})
::
q)selected:2
::
q)powers[selected]
{x*x}

The Identity Function ::

When :: is used with function application syntax, it is the identity function – i.e., it returns its input as output. 

The naked identity function cannot be used with prefix syntax; it must be enclosed in parentheses.

q)::[42]
42
q)::[`a`b`c]
`a`b`c
q):: 42 / error
`
q)(::) 42
42

Functions Are Data

q)(1; 98.6; {x*x})
1
98.6
{x*x}
q)f:{x*x}
q)(f; neg)[1; 5]
-5

Call-by-Name

q)a:42
q)get `a
42
q)`a set 43
`a
q)a
43

Local and Global Variables

Defining Local and Global Variables

A variable that is assigned with : within a function body is called a local variable.

q)f:{a:42; a+x}

As of this writing (Sep 2015), the maximum number of local variables permitted in a function is 24.

Some notes on local variables:

  • A local variable exists only for the duration of an application. There is no notion of a static local variable that maintains its value across applications.

  • A local variable is not visible outside its immediate scope of definition.

  • A local variable cannot be used as an argument to a q function that uses call-by-name.

  • A local variable is not visible within the body of a local function defined in the same scope. Otherwise put,

    q does not have lexical scoping.

    q)f:{[p1] a:42; helper:{[a; p2] a*p2}[a;]; helper p1} q)f 5 210

A variable assigned outside any function definition is called a global variable. Global variables are visible inside any function body.

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

As of this writing (Sep 2015), the maximum number of global variables that can be referenced in a function is 32. 

If this is a problem, redesign your code. For example collect values in a list or dictionary and pass that; the dictionary essentially provides pass-by-name.

Assigning Global Variables within a Function

This usage of :: is analogous to other forms of amend-in-place, such as +: or ,:, but using the assignment operator itself :. This accounts for its somewhat unintuitive properties – it is not truly a global assignment operator.

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

If there is a local variable having the same name as the global you intend to assign, double-colon assigns the local, not the global.

q)b:6
q)f:{b:42; b::x; b}
q)f[98]
98
q)b
6

We recommend against :: for global assignment. Instead, use set which truly does global assignment and doesn’t get hung up on a local-global name collision.

As we saw earlier, set uses call-by-name.

q)a:42
q)f:{a:98.6; `a set x}
q)f 43
`a
q)a
43

Projection

Projection means specifying only some of the parameters in function application, resulting in a function of the remaining parameters.

Function Projection

q)add:{x+y}
q)add[42;]
{x+y}[42;]
q)add[42;][3]
45
q)add3:{x+y+z}
q)add3[2][3][4]
9

Operator Projection

When used in infix form, a q operator can be projected by fixing its left operand (only). This requires parentheses.

q)(7*) 6
42

q)-[;42] 98
56

Multiple Projections

q){x+y+z}[1;;3]
{x+y+z}[1;;3]
q){x+y+z}[1;;3] 2
6

This is equivalent to projecting in the reverse order.

q){x+y+z}[;;3][1;]
{x+y+z}[;;3][1;]
q){x+y+z}[;;3][1;] 2
6

 Indexing at Depth

q)d:`a`b!(1 2 3; 100 200)
q)d[`a;1]
2

Atomic Functions

Unary Atomic Functions and "map"

q)neg 10 20 30
-10 -20 -30
q)neg `a`b`c!(10 20; 30 40 50; 60)
a| -10 -20
b| -30 -40 -50
c| -60

Binary Atomic Functions and zip

For example, Find (?) is atomic in only its second argument since it consumes the entire first argument in its search.

q)10 20 30?10
0
q)10 20 30?10 20 30 40 50
0 1 2 3 3
q)(enlist 10)?10
0

Similar behavior is achieved with "zip" in traditional and functional programming.

Creating Atomic Functions

Unary

q)f:{(x*x)+(2*x)-1}
q)f til 10
-1 2 7 14 23 34 47 62 79 98

Binary

q)pyth:{sqrt (x*x)+y*y}
q)pyth[1 2 3; 1 2 3]
1.414214 2.828427 4.242641

Iterators

Iterators (previously adverbs) are higher-order functions that modify the behavior of functions for application on lists.

Unary each

q)neg (1 2 3; 4 5)
-1 -2 -3
-4 -5
q)count 10 20 30
3
q)count each (10 20 30; 40 50)
3 2
q)each[count] (10 20 30; 40 50)
3 2

The higher-order function each is similar to "foreach" in imperative languages and is called "map" in functional programming languages.

q)(count each) each ((1 2 3; 3 4); (100 200; 300 400 500))
3 2
2 3
q)each[each[count]] ((1 2 3; 3 4); (100 200; 300 400 500))
3 2
2 3
q)(count each) each (1 2 3; 10 20 30)
1 1 1
1 1 1


q)reverse "live"
"evil"
q)reverse ("life"; "the"; "universe"; "and"; "everything")
"everything"
"and"
"universe"
"the"
"life"
q)reverse each ("life"; "the"; "universe"; "and"; "everything")
"efil"
"eht"
"esrevinu"
"dna"
"gnihtyreve"
q)neg each (1 2 3; 4 5)
-1 -2 -3
-4 -5
q)enlist each 1001 1002 1004 1003
1001
1002
1004
1003
q)flip enlist 1001 1002 1004 1003
1001
1002
1004
1003

Each '

An atomic operator automatically applies to corresponding pairs of items when applied to lists of the same length.

q)("abc"; "uv"),'("de"; "xyz")
"abcde"
"uvxyz"

There is no effect when the arguments are atoms.

q)3,'4
3 4

The modified function also extends an atom to match a list.

q)1,'10 20 30
1 10
1 20
1 30
q)2#'("abcde"; "fgh"; "ijklm")
"ab"
"fg"
"ij"


q)L1:(enlist `a; `b)
q)L2:1 2
q)L1,'L2
`a 1
`b 2

A reliable way to make a list of pairs from a pair of lists is:

q)flip (L1; L2)
,`a 1
`b 2

A nice example of ,' arises when both operands are tables. Since a table is a list of records, it is possible to apply ,' to tables with the same number of rows. 

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

出处:code.kx.com/q4m3/6\_Fun…

作者:Jeffry A. Borror