File: ms_transform.3

package info (click to toggle)
erlang-manpages 1%3A12.b.3-1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 4,188 kB
  • ctags: 2
  • sloc: makefile: 68; perl: 30; sh: 15
file content (516 lines) | stat: -rw-r--r-- 30,802 bytes parent folder | download
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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
.TH ms_transform 3 "stdlib  1.15.3" "Ericsson AB" "ERLANG MODULE DEFINITION"
.SH MODULE
ms_transform \- Parse_transform that translates fun syntax into match specifications\&. 
.SH DESCRIPTION
.LP
This module implements the parse_transform that makes calls to \fIets\fR and \fIdbg\fR:\fIfun2ms/1\fR translate into literal match specifications\&. It also implements the back end for the same functions when called from the Erlang shell\&.
.LP
The translations from fun\&'s to match_specs is accessed through the two "pseudo functions" \fIets:fun2ms/1\fR and \fIdbg:fun2ms/1\fR\&.
.LP
Actually this introduction is more or less an introduction to the whole concept of match specifications\&. Since everyone trying to use \fIets:select\fR or \fIdbg\fR seems to end up reading this page, it seems in good place to explain a little more than just what this module does\&.
.LP
There are some caveats one should be aware of, please read through the whole manual page if it\&'s the first time you\&'re using the transformations\&. 
.LP
Match specifications are used more or less as filters\&. They resemble usual Erlang matching in a list comprehension or in a \fIfun\fR used in conjunction with \fIlists:foldl\fR etc\&. The syntax of pure match specifications is somewhat awkward though, as they are made up purely by Erlang terms and there is no syntax in the language to make the match specifications more readable\&.
.LP
As the match specifications execution and structure is quite like that of a fun, it would for most programmers be more straight forward to simply write it using the familiar fun syntax and having that translated into a match specification automatically\&. Of course a real fun is more powerful than the match specifications allow, but bearing the match specifications in mind, and what they can do, it\&'s still more convenient to write it all as a fun\&. This module contains the code that simply translates the fun syntax into match_spec terms\&.
.LP
Let\&'s start with an ets example\&. Using \fIets:select\fR and a match specification, one can filter out rows of a table and construct a list of tuples containing relevant parts of the data in these rows\&. Of course one could use \fIets:foldl\fR instead, but the select call is far more efficient\&. Without the translation, one has to struggle with writing match specifications terms to accommodate this, or one has to resort to the less powerful \fIets:match(_object)\fR calls, or simply give up and use the more inefficient method of \fIets:foldl\fR\&. Using the \fIets:fun2ms\fR transformation, a \fIets:select\fR call is at least as easy to write as any of the alternatives\&.
.LP
As an example, consider a simple table of employees:

.nf
-record(emp, {empno,     %Employee number as a string, the key
              surname,   %Surname of the employee
              givenname, %Given name of employee
              dept,      %Department one of {dev,sales,prod,adm}
              empyear})\&. %Year the employee was employed    
.fi
.LP
We create the table using:

.nf
ets:new(emp_tab,[{keypos,#emp\&.empno},named_table,ordered_set])\&.    
.fi
.LP
Let\&'s also fill it with some randomly chosen data for the examples:

.nf
[{emp,"011103","Black","Alfred",sales,2000},
 {emp,"041231","Doe","John",prod,2001},
 {emp,"052341","Smith","John",dev,1997},
 {emp,"076324","Smith","Ella",sales,1995},
 {emp,"122334","Weston","Anna",prod,2002},
 {emp,"535216","Chalker","Samuel",adm,1998},
 {emp,"789789","Harrysson","Joe",adm,1996},
 {emp,"963721","Scott","Juliana",dev,2003},
 {emp,"989891","Brown","Gabriel",prod,1999}]    
.fi
.LP
Now, the amount of data in the table is of course to small to justify complicated ets searches, but on real tables, using \fIselect\fR to get exactly the data you want will increase efficiency remarkably\&.
.LP
Lets say for example that we\&'d want the employee numbers of everyone in the sales department\&. One might use \fIets:match\fR in such a situation:

.nf
1> ets:match(emp_tab, {\&'_\&', \&'$1\&', \&'_\&', \&'_\&', sales, \&'_\&'})\&.

[["011103"],["076324"]]    
.fi
.LP
Even though \fIets:match\fR does not require a full match specification, but a simpler type, it\&'s still somewhat unreadable, and one has little control over the returned result, it\&'s always a list of lists\&. OK, one might use \fIets:foldl\fR or \fIets:foldr\fR instead:

.nf
ets:foldr(fun(#emp{empno = E, dept = sales},Acc) -> [E | Acc];
             (_,Acc) -> Acc
          end,
          [],
          emp_tab)\&.    
.fi
.LP
Running that would result in \fI["011103", "076324"]\fR , which at least gets rid of the extra lists\&. The fun is also quite straightforward, so the only problem is that all the data from the table has to be transferred from the table to the calling process for filtering\&. That\&'s inefficient compared to the \fIets:match\fR call where the filtering can be done "inside" the emulator and only the result is transferred to the process\&. Remember that ets tables are all about efficiency, if it wasn\&'t for efficiency all of ets could be implemented in Erlang, as a process receiving requests and sending answers back\&. One uses ets because one wants performance, and therefore one wouldn\&'t want all of the table transferred to the process for filtering\&. OK, let\&'s look at a pure \fIets:select\fR call that does what the \fIets:foldr\fR does:

.nf
ets:select(emp_tab,[{#emp{empno = \&'$1\&', dept = sales, _=\&'_\&'},[],[\&'$1\&']}])\&.    
.fi
.LP
Even though the record syntax is used, it\&'s still somewhat hard to read and even harder to write\&. The first element of the tuple, \fI#emp{empno = \&'$1\&', dept = sales, _=\&'_\&'}\fR tells what to match, elements not matching this will not be returned at all, as in the \fIets:match\fR example\&. The second element, the empty list is a list of guard expressions, which we need none, and the third element is the list of expressions constructing the return value (in ets this almost always is a list containing one single term)\&. In our case \fI\&'$1\&'\fR is bound to the employee number in the head (first element of tuple), and hence it is the employee number that is returned\&. The result is \fI["011103", "076324"]\fR, just as in the \fIets:foldr\fR example, but the result is retrieved much more efficiently in terms of execution speed and memory consumption\&.
.LP
We have one efficient but hardly readable way of doing it and one inefficient but fairly readable (at least to the skilled Erlang programmer) way of doing it\&. With the use of \fIets:fun2ms\fR, one could have something that is as efficient as possible but still is written as a filter using the fun syntax:

.nf
-include_lib("stdlib/include/ms_transform\&.hrl")\&.

% \&.\&.\&.

ets:select(emp_tab, ets:fun2ms(
                      fun(#emp{empno = E, dept = sales}) ->
                              E
                      end))\&.    
.fi
.LP
This may not be the shortest of the expressions, but it requires no special knowledge of match specifications to read\&. The fun\&'s head should simply match what you want to filter out and the body returns what you want returned\&. As long as the fun can be kept within the limits of the match specifications, there is no need to transfer all data of the table to the process for filtering as in the \fIets:foldr\fR example\&. In fact it\&'s even easier to read then the \fIets:foldr\fR example, as the select call in itself discards anything that doesn\&'t match, while the fun of the \fIfoldr\fR call needs to handle both the elements matching and the ones not matching\&.
.LP
It\&'s worth noting in the above \fIets:fun2ms\fR example that one needs to include \fIms_transform\&.hrl\fR in the source code, as this is what triggers the parse transformation of the \fIets:fun2ms\fR call to a valid match specification\&. This also implies that the transformation is done at compile time (except when called from the shell of course) and therefore will take no resources at all in runtime\&. So although you use the more intuitive fun syntax, it gets as efficient in runtime as writing match specifications by hand\&.
.LP
Let\&'s look at some more \fIets\fR examples\&. Let\&'s say one wants to get all the employee numbers of any employee hired before the year 2000\&. Using \fIets:match\fR isn\&'t an alternative here as relational operators cannot be expressed there\&. Once again, an \fIets:foldr\fR could do it (slowly, but correct):

.nf
ets:foldr(fun(#emp{empno = E, empyear = Y},Acc) when Y < 2000 -> [E | Acc];
                  (_,Acc) -> Acc
          end,
          [],
          emp_tab)\&.    
.fi
.LP
The result will be \fI["052341", "076324", "535216", "789789", "989891"]\fR, as expected\&. Now the equivalent expression using a handwritten match specification would look something like this:

.nf
ets:select(emp_tab,[{#emp{empno = \&'$1\&', empyear = \&'$2\&', _=\&'_\&'},
                     [{\&'<\&', \&'$2\&', 2000}],
                     [\&'$1\&']}])\&.    
.fi
.LP
This gives the same result, the \fI[{\&'<\&', \&'$2\&', 2000}]\fR is in the guard part and therefore discards anything that does not have a empyear (bound to \&'$2\&' in the head) less than 2000, just as the guard in the \fIfoldl\fR example\&. Lets jump on to writing it using \fIets:fun2ms\fR

.nf
-include_lib("stdlib/include/ms_transform\&.hrl")\&.

% \&.\&.\&.

ets:select(emp_tab, ets:fun2ms(
                      fun(#emp{empno = E, empyear = Y}) when Y < 2000 ->
                              E
                      end))\&.    
.fi
.LP
Obviously readability is gained by using the parse transformation\&.
.LP
I\&'ll show some more examples without the tiresome comparing-to-alternatives stuff\&. Let\&'s say we\&'d want the whole object matching instead of only one element\&. We could of course assign a variable to every part of the record and build it up once again in the body of the \fIfun\fR, but it\&'s easier to do like this:

.nf
ets:select(emp_tab, ets:fun2ms(
                      fun(Obj = #emp{empno = E, empyear = Y}) 
                         when Y < 2000 ->
                              Obj
                      end))\&.    
.fi
.LP
Just as in ordinary Erlang matching, you can bind a variable to the whole matched object using a "match in then match", i\&.e\&. a \fI=\fR\&. Unfortunately this is not general in \fIfun\&'s\fR translated to match specifications, only on the "top level", i\&.e\&. matching the \fIwhole\fR object arriving to be matched into a separate variable, is it allowed\&. For the one\&'s used to writing match specifications by hand, I\&'ll have to mention that the variable A will simply be translated into \&'$_\&'\&. It\&'s not general, but it has very common usage, why it is handled as a special, but useful, case\&. If this bothers you, the pseudo function \fIobject\fR also returns the whole matched object, see the part about caveats and limitations below\&.
.LP
Let\&'s do something in the \fIfun\fR\&'s body too: Let\&'s say that someone realizes that there are a few people having an employee number beginning with a zero (\fI0\fR), which shouldn\&'t be allowed\&. All those should have their numbers changed to begin with a one (\fI1\fR) instead and one wants the list \fI[{<Old empno>, <New empno>}]\fR created:

.nf
ets:select(emp_tab, ets:fun2ms(
                      fun(#emp{empno = [$0 | Rest] }) ->
                              {[$0|Rest],[$1|Rest]}
                      end))\&.    
.fi
.LP
As a matter of fact, this query hit\&'s the feature of partially bound keys in the table type \fIordered_set\fR, so that not the whole table need be searched, only the part of the table containing keys beginning with \fI0\fR is in fact looked into\&. 
.LP
The fun of course can have several clauses, so that if one could do the following: For each employee, if he or she is hired prior to 1997, return the tuple \fI{inventory, <employee number>}\fR, for each hired 1997 or later, but before 2001, return \fI{rookie, <employee number>}\fR, for all others return \fI{newbie, <employee number>}\fR\&. All except for the ones named \fISmith\fR as they would be affronted by anything other than the tag \fIguru\fR and that is also what\&'s returned for their numbers; \fI{guru, <employee number>}\fR:

.nf
ets:select(emp_tab, ets:fun2ms(
                      fun(#emp{empno = E, surname = "Smith" }) ->
                              {guru,E};
                         (#emp{empno = E, empyear = Y}) when Y < 1997  ->
                              {inventory, E};
                         (#emp{empno = E, empyear = Y}) when Y > 2001  ->
                              {newbie, E};
                         (#emp{empno = E, empyear = Y}) -> % 1997 -- 2001
                              {rookie, E}
                      end))\&.    
.fi
.LP
The result will be:

.nf
[{rookie,"011103"},
 {rookie,"041231"},
 {guru,"052341"},
 {guru,"076324"},
 {newbie,"122334"},
 {rookie,"535216"},
 {inventory,"789789"},
 {newbie,"963721"},
 {rookie,"989891"}]    
.fi
.LP
and so the Smith\&'s will be happy\&.\&.\&.
.LP
So, what more can you do? Well, the simple answer would be; look in the documentation of match specifications in ERTS users guide\&. However let\&'s briefly go through the most useful "built in functions" that you can use when the \fIfun\fR is to be translated into a match specification by \fIets:fun2ms\fR (it\&'s worth mentioning, although it might be obvious to some, that calling other functions than the one\&'s allowed in match specifications cannot be done\&. No "usual" Erlang code can be executed by the \fIfun\fR being translated by \fIfun2ms\fR, the \fIfun\fR is after all limited exactly to the power of the match specifications, which is unfortunate, but the price one has to pay for the execution speed of an \fIets:select\fR compared to \fIets:foldl/foldr\fR)\&.
.LP
The head of the \fIfun\fR is obviously a head matching (or mismatching) \fIone\fR parameter, one object of the table we \fIselect\fR from\&. The object is always a single variable (can be \fI_\fR) or a tuple, as that\&'s what\&'s in \fIets, dets\fR and \fImnesia\fR tables (the match specification returned by \fIets:fun2ms\fR can of course be used with \fIdets:select\fR and \fImnesia:select\fR as well as with \fIets:select\fR)\&. The use of \fI=\fR in the head is allowed (and encouraged) on the top level\&.
.LP
The guard section can contain any guard expression of Erlang\&. Even the "old" type test are allowed on the toplevel of the guard (\fIinteger(X)\fR instead of \fIis_integer(X)\fR)\&. As the new type tests (the \fIis_\fR tests) are in practice just guard bif\&'s they can also be called from within the body of the fun, but so they can in ordinary Erlang code\&. Also arithmetics is allowed, as well as ordinary guard bif\&'s\&. Here\&'s a list of bif\&'s and expressions:
.RS 2
.TP 2
*
The type tests: is_atom, is_constant, is_float, is_integer, is_list, is_number, is_pid, is_port, is_reference, is_tuple, is_binary, is_function, is_record
.TP 2
*
The boolean operators: not, and, or, andalso, orelse
.TP 2
*
The relational operators: >, >=, <, =<, =:=, ==, =/=, /=
.TP 2
*
Arithmetics: +, -, *, div, rem
.TP 2
*
Bitwise operators: band, bor, bxor, bnot, bsl, bsr
.TP 2
*
The guard bif\&'s: abs, element, hd, length, node, round, size, tl, trunc, self
.TP 2
*
The obsolete type test (only in guards): atom, constant, float, integer, list, number, pid, port, reference, tuple, binary, function, record
.RE
.LP
Contrary to the fact with "handwritten" match specifications, the \fIis_record\fR guard works as in ordinary Erlang code\&.
.LP
Semicolons (\fI;\fR) in guards are allowed, the result will be (as expected) one "match_spec-clause" for each semicolon-separated part of the guard\&. The semantics beeing identical to the Erlang semantics\&.
.LP
The body of the \fIfun\fR is used to construct the resulting value\&. When selecting from tables one usually just construct a suiting term here, using ordinary Erlang term construction, like tuple parentheses, list brackets and variables matched out in the head, possibly in conjunction with the occasional constant\&. Whatever expressions are allowed in guards are also allowed here, but there are no special functions except \fIobject\fR and \fIbindings\fR (see further down), which returns the whole matched object and all known variable bindings respectively\&.
.LP
The \fIdbg\fR variants of match specifications have an imperative approach to the match specification body, the ets dialect hasn\&'t\&. The fun body for \fIets:fun2ms\fR returns the result without side effects, and as matching (\fI=\fR) in the body of the match specifications is not allowed (for performance reasons) the only thing left, more or less, is term construction\&.\&.\&.
.LP
Let\&'s move on to the \fIdbg\fR dialect, the slightly different match specifications translated by \fIdbg:fun2ms\fR\&. 
.LP
The same reasons for using the parse transformation applies to \fIdbg\fR, maybe even more so as filtering using Erlang code is simply not a good idea when tracing (except afterwards, if you trace to file)\&. The concept is similar to that of \fIets:fun2ms\fR except that you usually use it directly from the shell (which can also be done with \fIets:fun2ms\fR)\&. 
.LP
Let\&'s manufacture a toy module to trace on 

.nf
-module(toy)\&.

-export([start/1, store/2, retrieve/1])\&.

start(Args) ->
    toy_table = ets:new(toy_table,Args)\&.

store(Key, Value) ->
    ets:insert(toy_table,{Key,Value})\&.

retrieve(Key) ->
    [{Key, Value}] = ets:lookup(toy_table,Key),
    Value\&.    
.fi
.LP
During model testing, the first test bails out with a \fI{badmatch, 16}\fR in \fI{toy, start, 1}\fR, why?
.LP
We suspect the ets call, as we match hard on the return value, but want only the particular \fInew\fR call with \fItoy_table\fR as first parameter\&. So we start a default tracer on the node:

.nf
1> dbg:tracer()\&.

{ok,<0\&.88\&.0>}
.fi
.LP
And so we turn on call tracing for all processes, we are going to make a pretty restrictive trace pattern, so there\&'s no need to call trace only a few processes (it usually isn\&'t):

.nf
2> dbg:p(all,call)\&.

{ok,[{matched,nonode@nohost,25}]}    
.fi
.LP
It\&'s time to specify the filter\&. We want to view calls that resemble \fIets:new(toy_table, <something>)\fR:

.nf
3> dbg:tp(ets,new,dbg:fun2ms(fun([toy_table,_]) -> true end))\&.

{ok,[{matched,nonode@nohost,1},{saved,1}]}    
.fi
.LP
As can be seen, the \fIfun\fR\&'s used with \fIdbg:fun2ms\fR takes a single list as parameter instead of a single tuple\&. The list matches a list of the parameters to the traced function\&. A single variable may also be used of course\&. The body of the fun expresses in a more imperative way actions to be taken if the fun head (and the guards) matches\&. I return \fItrue\fR here, but it\&'s only because the body of a fun cannot be empty, the return value will be discarded\&. 
.LP
When we run the test of our module now, we get the following trace output:

.nf
(<0\&.86\&.0>) call ets:new(toy_table,[ordered_set])    
.fi
.LP
Let\&'s play we haven\&'t spotted the problem yet, and want to see what \fIets:new\fR returns\&. We do a slightly different trace pattern:

.nf
4> dbg:tp(ets,new,dbg:fun2ms(fun([toy_table,_]) -> return_trace() end))\&.

.fi
.LP
Resulting in the following trace output when we run the test:

.nf
(<0\&.86\&.0>) call ets:new(toy_table,[ordered_set])
(<0\&.86\&.0>) returned from ets:new/2 -> 24    
.fi
.LP
The call to \fIreturn_trace\fR, makes a trace message appear when the function returns\&. It applies only to the specific function call triggering the match specification (and matching the head/guards of the match specification)\&. This is the by far the most common call in the body of a \fIdbg\fR match specification\&.
.LP
As the test now fails with \fI{badmatch, 24}\fR, it\&'s obvious that the badmatch is because the atom \fItoy_table\fR does not match the number returned for an unnamed table\&. So we spotted the problem, the table should be named and the arguments supplied by our test program does not include \fInamed_table\fR\&. We rewrite the start function to:

.nf
start(Args) ->
    toy_table = ets:new(toy_table,[named_table |Args])\&.    
.fi
.LP
And with the same tracing turned on, we get the following trace output:

.nf
(<0\&.86\&.0>) call ets:new(toy_table,[named_table,ordered_set])
(<0\&.86\&.0>) returned from ets:new/2 -> toy_table    
.fi
.LP
Very well\&. Let\&'s say the module now passes all testing and goes into the system\&. After a while someone realizes that the table \fItoy_table\fR grows while the system is running and that for some reason there are a lot of elements with atom\&'s as keys\&. You had expected only integer keys and so does the rest of the system\&. Well, obviously not all of the system\&. You turn on call tracing and try to see calls to your module with an atom as the key:

.nf
1> dbg:tracer()\&.

{ok,<0\&.88\&.0>}
2> dbg:p(all,call)\&.

{ok,[{matched,nonode@nohost,25}]}
3> dbg:tpl(toy,store,dbg:fun2ms(fun([A,_]) when is_atom(A) -> true end))\&.

{ok,[{matched,nonode@nohost,1},{saved,1}]}
.fi
.LP
We use \fIdbg:tpl\fR here to make sure to catch local calls (let\&'s say the module has grown since the smaller version and we\&'re not sure this inserting of atoms is not done locally\&.\&.\&.)\&. When in doubt always use local call tracing\&.
.LP
Let\&'s say nothing happens when we trace in this way\&. Our function is never called with these parameters\&. We make the conclusion that someone else (some other module) is doing it and we realize that we must trace on ets:insert and want to see the calling function\&. The calling function may be retrieved using the match specification function \fIcaller\fR and to get it into the trace message, one has to use the match spec function \fImessage\fR\&. The filter call looks like this (looking for calls to \fIets:insert\fR):

.nf
4> dbg:tpl(ets,insert,dbg:fun2ms(fun([toy_table,{A,_}]) when is_atom(A) -> 

                                    message(caller()) 

                                  end))\&. 

{ok,[{matched,nonode@nohost,1},{saved,2}]}    
.fi
.LP
The caller will now appear in the "additional message" part of the trace output, and so after a while, the following output comes:

.nf
(<0\&.86\&.0>) call ets:insert(toy_table,{garbage,can}) ({evil_mod,evil_fun,2})    
.fi
.LP
You have found out that the function \fIevil_fun\fR of the module \fIevil_mod\fR, with arity \fI2\fR, is the one causing all this trouble\&.
.LP
This was just a toy example, but it illustrated the most used calls in match specifications for \fIdbg\fR The other, more esotherical calls are listed and explained in the \fIUsers guide of the ERTS application\fR, they really are beyond the scope of this document\&.
.LP
To end this chatty introduction with something more precise, here follows some parts about caveats and restrictions concerning the fun\&'s used in conjunction with \fIets:fun2ms\fR and \fIdbg:fun2ms\fR:
.SS Warning:
.LP
To use the pseudo functions triggering the translation, one \fIhas to\fR include the header file \fIms_transform\&.hrl\fR in the source code\&. Failure to do so will possibly result in runtime errors rather than compile time, as the expression may be valid as a plain Erlang program without translation\&.

.SS Warning:
.LP
The \fIfun\fR has to be literally constructed inside the parameter list to the pseudo functions\&. The \fIfun\fR cannot be bound to a variable first and then passed to \fIets:fun2ms\fR or \fIdbg:fun2ms\fR, i\&.e this will work: \fIets:fun2ms(fun(A) -> A end)\fR but not this: \fIF = fun(A) -> A end, ets:fun2ms(F)\fR\&. The later will result in a compile time error if the header is included, otherwise a runtime error\&. Even if the later construction would ever appear to work, it really doesn\&'t, so don\&'t ever use it\&.

.LP
Several restrictions apply to the fun that is being translated into a match_spec\&. To put it simple you cannot use anything in the fun that you cannot use in a match_spec\&. This means that, among others, the following restrictions apply to the fun itself:
.RS 2
.TP 2
*
Functions written in Erlang cannot be called, neither local functions, global functions or real fun\&'s
.TP 2
*
Everything that is written as a function call will be translated into a match_spec call to a builtin function, so that the call \fIis_list(X)\fR will be translated to \fI{\&'is_list\&', \&'$1\&'}\fR (\fI\&'$1\&'\fR is just an example, the numbering may vary)\&. If one tries to call a function that is not a match_spec builtin, it will cause an error\&.
.TP 2
*
Variables occurring in the head of the \fIfun\fR will be replaced by match_spec variables in the order of occurrence, so that the fragment \fIfun({A, B, C})\fR will be replaced by \fI{\&'$1\&', \&'$2\&', \&'$3\&'}\fR etc\&. Every occurrence of such a variable later in the match_spec will be replaced by a match_spec variable in the same way, so that the fun \fIfun({A, B}) when is_atom(A) -> B end\fR will be translated into \fI[{{\&'$1\&', \&'$2\&'}, [{is_atom, \&'$1\&'}], [\&'$2\&']}]\fR\&.
.TP 2
*
Variables that are not appearing in the head are imported from the environment and made into match_spec \fIconst\fR expressions\&. Example from the shell:
.RS 2
.LP


.nf
1> X = 25\&.

25
2> ets:fun2ms(fun({A,B}) when A > X -> B end)\&.

[{{\&'$1\&',\&'$2\&'},[{\&'>\&',\&'$1\&',{const,25}}],[\&'$2\&']}]
.fi
.RE
.TP 2
*
Matching with \fI=\fR cannot be used in the body\&. It can only be used on the top level in the head of the fun\&. Example from the shell again:
.RS 2
.LP


.nf
1> ets:fun2ms(fun({A,[B|C]} = D) when A > B -> D end)\&.

[{{\&'$1\&',[\&'$2\&'|\&'$3\&']},[{\&'>\&',\&'$1\&',\&'$2\&'}],[\&'$_\&']}]
2> ets:fun2ms(fun({A,[B|C]=D}) when A > B -> D end)\&.

Error: fun with head matching (\&'=\&' in head) cannot be translated into 
match_spec 
{error,transform_error}
3> ets:fun2ms(fun({A,[B|C]}) when A > B -> D = [B|C], D end)\&.

Error: fun with body matching (\&'=\&' in body) is illegal as match_spec
{error,transform_error}        
.fi
.LP

.LP
All variables are bound in the head of a match_spec, so the translator can not allow multiple bindings\&. The special case when matching is done on the top level makes the variable bind to \fI\&'$_\&'\fR in the resulting match_spec, it is to allow a more natural access to the whole matched object\&. The pseudo function \fIobject()\fR could be used instead, see below\&. The following expressions are translated equally: 
.LP


.nf
ets:fun2ms(fun({a,_} = A) -> A end)\&.
ets:fun2ms(fun({a,_}) -> object() end)\&.               
.fi
.RE
.TP 2
*
The special match_spec variables \fI\&'$_\&'\fR and \fI\&'$*\&'\fR can be accessed through the pseudo functions \fIobject()\fR (for \fI\&'$_\&'\fR) and \fIbindings()\fR (for \fI\&'$*\&'\fR)\&. as an example, one could translate the following \fIets:match_object/2\fR call to a \fIets:select\fR call:
.RS 2
.LP


.nf
ets:match_object(Table, {\&'$1\&',test,\&'$2\&'})\&. 
.fi
.LP

.LP
\&.\&.\&.is the same as\&.\&.\&.
.LP


.nf
ets:select(Table, ets:fun2ms(fun({A,test,B}) -> object() end))\&.
.fi
.LP

.LP
(This was just an example, in this simple case the former expression is probably preferable in terms of readability)\&. The \fIets:select/2\fR call will conceptually look like this in the resulting code:
.LP


.nf
ets:select(Table, [{{\&'$1\&',test,\&'$2\&'},[],[\&'$_\&']}])\&.
.fi
.LP

.LP
Matching on the top level of the fun head might feel like a more natural way to access \fI\&'$_\&'\fR, see above\&.
.RE
.TP 2
*
Term constructions/literals are translated as much as is needed to get them into valid match_specs, so that tuples are made into match_spec tuple constructions (a one element tuple containing the tuple) and constant expressions are used when importing variables from the environment\&. Records are also translated into plain tuple constructions, calls to element etc\&. The guard test \fIis_record/2\fR is translated into match_spec code using the three parameter version that\&'s built into match_specs, so that \fIis_record(A, t)\fR is translated into \fI{is_record, \&'$1\&', t, 5}\fR given that the record size of record type \fIt\fR is 5\&.
.TP 2
*
Language constructions like \fIcase\fR, \fIif\fR, \fIcatch\fR etc that are not present in match_specs are not allowed\&.
.TP 2
*
If the header file \fIms_transform\&.hrl\fR is not included, the fun won\&'t be translated, which may result in a \fIruntime error\fR (depending on if the fun is valid in a pure Erlang context)\&. Be absolutely sure that the header is included when using \fIets\fR and \fIdbg:fun2ms/1\fR in compiled code\&.
.TP 2
*
If the pseudo function triggering the translation is \fIets:fun2ms/1\fR, the fun\&'s head must contain a single variable or a single tuple\&. If the pseudo function is \fIdbg:fun2ms/1\fR the fun\&'s head must contain a single variable or a single list\&.
.RE
.LP
The translation from fun\&'s to match_specs is done at compile time, so runtime performance is not affected by using these pseudo functions\&. The compile time might be somewhat longer though\&. 
.LP
For more information about match_specs, please read about them in \fIERTS users guide\fR\&.

.SH EXPORTS
.LP
.B
parse_transform(Forms,_Options) -> Forms
.br
.RS
.TP
Types
Forms = Erlang abstract code format, see the erl_parse module description 
.br
_Options = Option list, required but not used
.br
.RE
.RS
.LP
Implements the actual transformation at compile time\&. This function is called by the compiler to do the source code transformation if and when the \fIms_transform\&.hrl\fR header file is included in your source code\&. See the \fIets\fR and \fIdbg\fR:\fIfun2ms/1\fR function manual pages for documentation on how to use this parse_transform, see the \fImatch_spec\fR chapter in \fIERTS\fR users guide for a description of match specifications\&. 
.RE
.LP
.B
transform_from_shell(Dialect,Clauses,BoundEnvironment) -> term()
.br
.RS
.TP
Types
Dialect = ets | dbg
.br
Clauses = Erlang abstract form for a single fun
.br
BoundEnvironment = [{atom(), term()}, \&.\&.\&.], list of variable bindings in the shell environment
.br
.RE
.RS
.LP
Implements the actual transformation when the \fIfun2ms\fR functions are called from the shell\&. In this case the abstract form is for one single fun (parsed by the Erlang shell), and all imported variables should be in the key-value list passed as \fIBoundEnvironment\fR\&. The result is a term, normalized, i\&.e\&. not in abstract format\&.
.RE
.LP
.B
format_error(Errcode) -> ErrMessage
.br
.RS
.TP
Types
Errcode = term()
.br
ErrMessage = string()
.br
.RE
.RS
.LP
Takes an error code returned by one of the other functions in the module and creates a textual description of the error\&. Fairly uninteresting function actually\&.
.RE