1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
|
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
<year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
The contents of this file are subject to the Erlang Public License,
Version 1.1, (the "License"); you may not use this file except in
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
</legalnotice>
<title>Maps</title>
<prepared></prepared>
<docno></docno>
<date></date>
<rev></rev>
<file>maps.xml</file>
</header>
<note>
<p>Maps are considered experimental during OTP 17 and may be subject to change.</p>
<p>The documentation below describes it being possible to use arbitrary
expressions or variables as keys, this is <em>NOT</em> implemented in the current
version of Erlang/OTP.</p>
<p>Exceptions returns <c>badarg</c> instead of <c>badmap</c>, this will change in
the future releases.</p>
</note>
<section>
<title>Creating Maps</title>
<p>
Constructing a new map is done by letting an expression <c>K</c> be associated with
another expression <c>V</c>:
</p>
<code>#{ K => V }</code>
<p>
New maps may include multiple associations at construction by listing every
association:
</p>
<code>#{ K1 => V1, .., Kn => Vn }</code>
<p>
An empty map is constructed by not associating any terms with each other:
</p>
<code>#{}</code>
<p>
All keys and values in the map are terms. Any expression is first evaluated and
then the resulting terms are used as <em>key</em> and <em>value</em> respectively.
</p>
<p>
Keys and values are separated by the <c>=></c> arrow and associations are
separated by <c>,</c>.
</p>
<p>
Examples:
</p>
<code>
M0 = #{}, % empty map
M1 = #{a => <<"hello">>}, % single association with literals
M2 = #{1 => 2, b => b}, % multiple associations with literals
M3 = #{k => {A,B}}, % single association with variables
M4 = #{{"w", 1} => f()}. % compound key associated with an evaluated expression</code>
<p>
where, <c>A</c> and <c>B</c> are any expressions and <c>M0</c> through <c>M4</c>
are the resulting map terms.
</p>
<p>
If two matching keys are declared, the latter key will take precedence.
</p>
<p>
Example:
</p>
<pre>
1> <input>#{1 => a, 1 => b}.</input>
#{1 => b }
2> <input>#{1.0 => a, 1 => b}.</input>
#{1 => b, 1.0 => a}
</pre>
<p>
The order in which the expressions constructing the keys and their
associated values are evaluated is not defined. The syntactic order of
the key-value pairs in the construction is of no relevance, except in
the above mentioned case of two matching keys.
</p>
</section>
<section>
<title>Updating Maps</title>
<p>
Updating a map has similar syntax as constructing it.
</p>
<p>
An expression defining the map to be updated is put in front of the expression
defining the keys to be updated and their respective values.
</p>
<code>M#{ K => V }</code>
<p>
where <c>M</c> is a term of type map and <c>K</c> and <c>V</c> are any expression.
</p>
<p>
If key <c>K</c> does not match any existing key in the map, a new association
will be created from key <c>K</c> to value <c>V</c>. If key <c>K</c> matches
an existing key in map <c>M</c> its associated value will be replaced by the
new value <c>V</c>. In both cases the evaluated map expression will return a new map.
</p>
<p>
If <c>M</c> is not of type map an exception of type <c>badmap</c> is thrown.
</p>
<p>
To only update an existing value, the following syntax is used,
</p>
<code>M#{ K := V } </code>
<p>
where <c>M</c> is an term of type map, <c>V</c> is an expression and <c>K</c>
is an expression which evaluates to an existing key in <c>M</c>.
</p>
<p>
If key <c>K</c> does not match any existing keys in map <c>M</c> an exception
of type <c>badarg</c> will be triggered at runtime. If a matching key <c>K</c>
is present in map <c>M</c> its associated value will be replaced by the new
value <c>V</c> and the evaluated map expression returns a new map.
</p>
<p>
If <c>M</c> is not of type map an exception of type <c>badmap</c> is thrown.
</p>
<p>
Examples:
</p>
<code>
M0 = #{},
M1 = M0#{a => 0},
M2 = M1#{a => 1, b => 2},
M3 = M2#{"function" => fun() -> f() end},
M4 = M3#{a := 2, b := 3}. % 'a' and 'b' was added in `M1` and `M2`.</code>
<p>
where <c>M0</c> is any map. It follows that <c>M1 .. M4</c> are maps as well.
</p>
<p>
More Examples:
</p>
<pre>
1> <input>M = #{1 => a}.</input>
#{1 => a }
2> <input>M#{1.0 => b}.</input>
#{1 => a, 1.0 => b}.
3> <input>M#{1 := b}.</input>
#{1 => b}
4> <input>M#{1.0 := b}.</input>
** exception error: bad argument
</pre>
<p>
As in construction, the order in which the key and value expressions
are evaluated is not defined. The
syntactic order of the key-value pairs in the update is of no
relevance, except in the case where two keys match, in which
case the latter value is used.
</p>
</section>
<section>
<title>Maps in Patterns</title>
<p>
Matching of key-value associations from maps is done in the following way:
</p>
<code>#{ K := V } = M</code>
<p>
where <c>M</c> is any map. The key <c>K</c> has to be an expression with bound
variables or a literals, and <c>V</c> can be any pattern with either bound or
unbound variables.
</p>
<p>
If the variable <c>V</c> is unbound, it will be bound to the value associated
with the key <c>K</c>, which has to exist in the map <c>M</c>. If the variable
<c>V</c> is bound, it has to match the value associated with <c>K</c> in <c>M</c>.
</p>
<p> Example: </p>
<code>
1> <input>M = #{"tuple" => {1,2}}.</input>
#{"tuple" => {1,2}}
2> <input>#{"tuple" := {1,B}} = M.</input>
#{"tuple" => {1,2}}
3> <input>B.</input>
2.</code>
<p>
This will bind variable <c>B</c> to integer <c>2</c>.
</p>
<p>
Similarly, multiple values from the map may be matched:
</p>
<code>#{ K1 := V1, .., Kn := Vn } = M</code>
<p>
where keys <c>K1 .. Kn</c> are any expressions with literals or bound variables. If all
keys exist in map <c>M</c> all variables in <c>V1 .. Vn</c> will be matched to the
associated values of their respective keys.
</p>
<p>
If the matching conditions are not met, the match will fail, either with
</p>
<list>
<item>
a <c>badmatch</c> exception, if used in the context of the matching operator
as in the example,
</item>
<item>
or resulting in the next clause being tested in function heads and
case expressions.
</item>
</list>
<p>
Matching in maps only allows for <c>:=</c> as delimiters of associations.
The order in which keys are declared in matching has no relevance.
</p>
<p>
Duplicate keys are allowed in matching and will match each pattern associated
to the keys.
</p>
<code>#{ K := V1, K := V2 } = M</code>
<p>
Matching an expression against an empty map literal will match its type but
no variables will be bound:
</p>
<code>#{} = Expr</code>
<p>
This expression will match if the expression <c>Expr</c> is of type map, otherwise
it will fail with an exception <c>badmatch</c>.
</p>
<section>
<title>Matching syntax: Example with literals in function heads</title>
<p>
Matching of literals as keys are allowed in function heads.
</p>
<code>
%% only start if not_started
handle_call(start, From, #{ state := not_started } = S) ->
...
{reply, ok, S#{ state := start }};
%% only change if started
handle_call(change, From, #{ state := start } = S) ->
...
{reply, ok, S#{ state := changed }};</code>
</section>
</section>
<section>
<title>Maps in Guards</title>
<p>
Maps are allowed in guards as long as all sub-expressions are valid guard expressions.
</p>
<p>
Two guard BIFs handles maps:
</p>
<list>
<item>
<seealso marker="erts:erlang#is_map/1">is_map/1</seealso>
</item>
<item>
<seealso marker="erts:erlang#map_size/1">map_size/1</seealso>
</item>
</list>
</section>
</chapter>
|