Skip to content

Commit e864673

Browse files
Merge pull request #381 from gyorokpeter/match
docs for pattern matching
2 parents a614f7b + cce843d commit e864673

File tree

6 files changed

+262
-2
lines changed

6 files changed

+262
-2
lines changed

docs/basics/function-notation.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ q){(x*x)+(y*y)+2*x*y}[20;4] / unsigned lambda
4848

4949
Using other names for the first arguments of a lambda often helps the reader. But using `x`, `y`, or `z` for any other argument sows confusion.
5050

51+
### Pattern matching
52+
53+
The function signature can include patterns - see [pattern matching](pattern.md#function-parameters).
5154

5255
## Rank
5356

docs/basics/pattern.md

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
---
2+
title: Pattern matching | Basics | kdb+ and q documentation
3+
description: Pattern matching in assignments and function parameters
4+
author: Péter Györök
5+
---
6+
# Pattern Matching
7+
8+
Pattern matching allows an object such as a list or dictionary to be matched to a pattern, assigning variables to its parts, checking types, and/or modifying values via a filter function. It can simplify unpacking multiple objects passed to and returned from functions, and reduce the overhead of type checking.
9+
10+
## Assignment
11+
12+
The left side of the [assignment](../ref/assign.md) operator may be a pattern. Various kinds of patterns have different effects. When used in an assignment, the pattern must have parentheses around it. A failed match results in no variables being changed.
13+
14+
```q
15+
q)(b;c):2 3
16+
q)b
17+
2
18+
q)c
19+
3
20+
```
21+
22+
The return value of the match is the entire assigned object, including any modifications from filter functions.
23+
24+
```q
25+
q)a:(b;:1+):1 2
26+
q)a
27+
1 3
28+
q)b
29+
1
30+
```
31+
32+
## Function parameters
33+
34+
Pattern matching can also be used in the parameter list of a [function](function-notation.md), in which case the parentheses are not necessary unless the pattern requires them (such as a list pattern).
35+
36+
```q
37+
q)f:{[(a;b);c]a+b+c}
38+
q)f[1 2;3]
39+
6
40+
```
41+
42+
## Pattern conditional
43+
44+
The pattern conditional takes the form `:[v;p1;r1;p2;r2;...;rd]` where `v` is a value to be matched, `p1`, `p2`, ... are patterns and `r1`, `r2`, ... `rd` are the corresponding return values. The value is matched to the patterns in turn, and the value of the expression is the return value corresponding to the first successful match, or `rd` if no patterns match. Similarly to the regular [conditional](../ref/cond.md), the result expressions corresponding to failed matches, as well as any match after the first successful match, are not evaluated.
45+
46+
```q
47+
q)a: :[1f;r:`f;"float";r:`i;"int";"other"]
48+
q)a
49+
"float"
50+
q)r
51+
1f
52+
q)a: :[1i;r:`f;"float";r:`i;"int";"other"]
53+
q)r
54+
1i
55+
q)a
56+
"int"
57+
q)a: :[1;r:`f;"float";r:`i;"int";"other"]
58+
q)a
59+
"other"
60+
```
61+
62+
## Types of patterns
63+
64+
### Null
65+
66+
The null pattern matches anything. It cannot be used as the main pattern in an assignment, but it can appear as a component of more complex patterns by elision.
67+
68+
### Constant value
69+
70+
The simplest pattern is a constant (atom or list). If the assigned value exactly matches (see [~](../ref/match.md)), the assignment does nothing. If the values don't match, a `'match` error is thrown.
71+
72+
```q
73+
q)(1):1
74+
q)(`a):`a
75+
q)(1):2
76+
'match
77+
[0] (1):2
78+
^
79+
q)(1 2):1 2
80+
q)(1 2):1 3
81+
'match
82+
[0] (1 2):1 3
83+
^
84+
```
85+
86+
### Name
87+
88+
A name is an identifier used as a pattern. The variable with the name is set to the matched value. On its own, this is equivalent to a simple assignment, but a name pattern can be used as a component of more complex patterns.
89+
90+
```q
91+
q)(a):1 3
92+
q)a
93+
1 3
94+
```
95+
96+
### Name with index
97+
98+
A name can be augmented with an index, similar to [indexed assignment](../ref/assign.md#indexed-assign). The index is not a pattern but a value.
99+
100+
```q
101+
q)a:1 2 3
102+
q)(a[1]):4
103+
q)a
104+
1 4 3
105+
```
106+
107+
### List
108+
109+
A list pattern looks like a [general list](syntax.md#list-notation). Each element of the list is a pattern itself. Combined with name patterns, this can be used to assign multiple variables in a single assignment.
110+
111+
```q
112+
q)(b;c):2 3
113+
q)b
114+
2
115+
q)c
116+
3
117+
```
118+
119+
The length of the pattern must match the length of the assigned value, and each element is matched in turn.
120+
121+
```q
122+
q)(b;c):2 3 4
123+
'length
124+
q)(b;c;3):2 3 4
125+
'match
126+
[0] (b;c;3):2 3 4
127+
^
128+
```
129+
130+
Since a table can be used as a list, it can match a list pattern:
131+
132+
```q
133+
q)(a;b):([]colA:1 2;colB:3 4)
134+
q)a
135+
colA| 1
136+
colB| 3
137+
q)b
138+
colA| 2
139+
colB| 4
140+
```
141+
142+
Null patterns can be used by eliding items from the list pattern. In this case, the element is checked for existence but its value is not matched.
143+
144+
```q
145+
q)(a;b;):1 2
146+
'length
147+
[0] (a;b;):1 2
148+
^
149+
q)(a;b;):1 2 3
150+
```
151+
152+
### Dictionary
153+
154+
A dictionary pattern can be made using the [!](../ref/dict.md) operator or using the bracketed dictionary syntax. Each _value_ in the dictionary is a pattern. The values are matched with those with the same key in the assigned value. The assigned value may have additional keys that are ignored.
155+
156+
```q
157+
q)(1 2!(one;two)):1 2!"ab"
158+
q)one
159+
"a"
160+
q)two
161+
"b"
162+
q)(1 2!(one;two)):1 2 3!"abc"
163+
q)(1 2!(one;two)):1 3!"ac"
164+
'match
165+
[0] (1 2!(one;two)):1 3!"ac"
166+
^
167+
q)([four:d]):`one`two`three`four`five!1 2 3 4 5
168+
q)d
169+
4
170+
```
171+
172+
As with lists, null patterns can be used. For the bracketed syntax, this means not putting a value after the colon for a key.
173+
174+
```q
175+
q)([one:;four:d]):`one`two`three`four`five!1 2 3 4 5
176+
q)([six:;four:d]):`one`two`three`four`five!1 2 3 4 5
177+
'match
178+
[0] ([six:;four:d]):`one`two`three`four`five!1 2 3 4 5
179+
^
180+
```
181+
182+
### Table
183+
184+
Tables can also be used as patterns similarly to dictionaries.
185+
186+
```q
187+
q)([]cc:e):([]aa:1 2;bb:3 4;cc:5 6)
188+
q)e
189+
5 6
190+
q)([k1:f]cc:e):([k1:7 8]aa:1 2;bb:3 4;cc:5 6)
191+
q)f
192+
7 8
193+
```
194+
195+
### Operator
196+
197+
Certain operators can be used as patterns. Currently only [!](../ref/dict.md) and [`flip`](../ref/flip.md) (for dict-to-table conversion) can be used in this way.
198+
199+
```q
200+
q)(flip([a;b])):([]a:1 2;b:3 4)
201+
q)a
202+
1 2
203+
q)b
204+
3 4
205+
q)(a!b):1 2!"ab"
206+
q)a
207+
1 2
208+
q)b
209+
"ab"
210+
q)(a!):1 2!3 4
211+
q)a
212+
1 2
213+
```
214+
215+
### Type check
216+
217+
The type check pattern takes the form ```p:`x```, where `p` is a pattern (including the null pattern) and `x` is the [type character](datatypes.md) for the type being checked. A lowercase letter matches an atom and an uppercase letter matches a list. If the type is correct, the pattern match proceeds to `p`, otherwise a `'type` error is thrown.
218+
219+
```q
220+
q)(:`f):3f
221+
q)(:`f):3e
222+
'type
223+
[0] (:`f):3e
224+
^
225+
q)((a;b):`F):3 4f
226+
q)a
227+
3f
228+
q)b
229+
4f
230+
q)((a;b):`F):3 4e
231+
'type
232+
[0] ((a;b):`F):3 4e
233+
^
234+
```
235+
236+
### Filter function
237+
238+
The filter function pattern takes the form ```p:expr``` where `expr` is an expression that returns a callable (such as a lambda, projection or operator). The result of `expr` is called on the value from the assigned value, and the result is matched to `p`.
239+
240+
```q
241+
q)(a:3+):4
242+
q)a
243+
7
244+
q)tempCheck:{$[x<0;'"too cold";x>40;'"too hot";x]}
245+
q)c2f:{[x:tempCheck]32+1.8*x}
246+
q)c2f -4.5
247+
'too cold
248+
q)c2f 42.8
249+
'too hot
250+
q)c2f 20
251+
68f
252+
```

docs/ref/assign.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ q)bar
121121
1
122122
```
123123

124+
## Pattern match
125+
126+
See [Pattern matching](../basics/pattern.md#assignment)
127+
124128
## Syntax
125129

126130
An expression with an assignment on the left returns no value to the console.

docs/ref/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ author: Stephen Taylor
9696

9797
<div markdown class="typewriter">
9898
[.[f;x;e] Trap](../ref/apply.md#trap) [: Return](../basics/function-notation.md#explicit-return) [do](../ref/do.md) [exit](../ref/exit.md) [\$[x;y;z] Cond](../ref/cond.md)
99-
[@[f;x;e] Trap-At](../ref/apply.md#trap) [' Signal](../ref/signal.md) [if](../ref/if.md) [while](../ref/while.md)
99+
[@[f;x;e] Trap-At](../ref/apply.md#trap) [' Signal](../ref/signal.md) [if](../ref/if.md) [while](../ref/while.md) [:[v;p1;r1;...] Pattern conditional](../basics/pattern.md#pattern-conditional)
100100
</div>
101101

102102
:fontawesome-solid-book-open:

local.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ if [ $# -eq 0 ]; then
3535
docker_image="$(cat docker-image-name.txt):$(cat docker-image-version.txt)"
3636
cmd="build --clean -s -f local.yml --no-directory-urls --site-dir $localdir"
3737
echo "### Using docs in $localdir/ using docker image $docker_image"
38-
docker run --rm -v $(pwd):$work_dir --workdir $work_dir $docker_image $cmd
38+
docker run --rm -v $(pwd):$work_dir --workdir $work_dir --user $(id -u):$(id -g) $docker_image $cmd
3939
else
4040
cat mkdocs.yml | sed \
4141
-e 's#^INHERIT.*##' \

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ nav:
416416
- Mathematics: basics/math.md
417417
- Metadata: basics/metadata.md
418418
- Namespaces: basics/namespaces.md
419+
- Pattern matching: basics/pattern.md
419420
- Parse trees: basics/parsetrees.md
420421
- qSQL:
421422
- qSQL queries: basics/qsql.md

0 commit comments

Comments
 (0)