~ubuntu-branches/ubuntu/hardy/ocaml-doc/hardy

« back to all changes in this revision

Viewing changes to camlp4-tutorial.html/tutorial007.html

  • Committer: Bazaar Package Importer
  • Author(s): Samuel Mimram
  • Date: 2007-09-08 01:49:22 UTC
  • mfrom: (0.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20070908014922-lvihyehz0ndq7suu
Tags: 3.10-1
* New upstream release.
* Removed camlp4 documentation since it is not up-to-date.
* Updated to standards version 3.7.2, no changes needed.
* Updated my email address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
2
 
            "http://www.w3.org/TR/REC-html40/loose.dtd">
3
 
<HTML>
4
 
<HEAD>
5
 
 
6
 
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
7
 
<META name="GENERATOR" content="hevea 1.06">
8
 
<TITLE>
9
 
 Extending the syntax of OCaml
10
 
</TITLE>
11
 
</HEAD>
12
 
<BODY TEXT=black BGCOLOR=white>
13
 
<A HREF="tutorial006.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
14
 
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Up"></A>
15
 
<A HREF="tutorial008.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
16
 
<HR>
17
 
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
18
 
<TR><TD BGCOLOR="#2de52d"><DIV ALIGN=center><TABLE>
19
 
<TR><TD><A NAME="htoc56"><B><FONT SIZE=6>Chapter&nbsp;7</FONT></B></A></TD>
20
 
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=6>Extending the syntax of OCaml</FONT></B></TD>
21
 
</TR></TABLE></DIV></TD>
22
 
</TR></TABLE>
23
 
<A NAME="c:tutext"></A>
24
 
<A NAME="toc48"></A><TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
25
 
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
26
 
<TR><TD><A NAME="htoc57"><B><FONT SIZE=5>7.1</FONT></B></A></TD>
27
 
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Introduction</FONT></B></TD>
28
 
</TR></TABLE></DIV></TD>
29
 
</TR></TABLE><BR>
30
 
Syntax extensions in <CODE>OCaml</CODE> can be done by extending the
31
 
grammars entries of the OCaml syntax. All grammars entries are defined
32
 
in the module named <CODE>Pcaml</CODE>. They all return values of types
33
 
defined in the module <CODE>MLast</CODE>: nodes of these types can be
34
 
created using the predefined quotation expansion <CODE>q_MLast.cmo</CODE>.<BR>
35
 
<BR>
36
 
 
37
 
 
38
 
The entries in <CODE>Pcaml</CODE> are:
39
 
<UL><LI><CODE>expr</CODE> for expressions, returning values of type
40
 
<CODE>MLast.expr</CODE>.<BR>
41
 
<BR>
42
 
<LI><CODE>patt</CODE> for patterns, returning values of type
43
 
<CODE>MLast.patt</CODE>.<BR>
44
 
<BR>
45
 
<LI><CODE>ctyp</CODE> for types, returning values of type
46
 
<CODE>MLast.ctyp</CODE>.<BR>
47
 
<BR>
48
 
<LI><CODE>module_type</CODE> for module types, returning values of type
49
 
<CODE>MLast.module_type</CODE>.<BR>
50
 
<BR>
51
 
<LI><CODE>module_expr</CODE> for module expressions, returning values of type
52
 
<CODE>MLast.module_expr</CODE>.<BR>
53
 
<BR>
54
 
<LI><CODE>sig_item</CODE> for signature items, returning values of type
55
 
<CODE>MLast.sig_item</CODE>.<BR>
56
 
<BR>
57
 
<LI><CODE>str_item</CODE> for structure items, returning values of type
58
 
<CODE>MLast.str_item</CODE>.</UL>
59
 
Most of these entries are generally defined (``extended'') with
60
 
several ``levels'' (see chapter <A HREF="tutorial003.html#c:tutgram">3</A>). Some of them
61
 
are labelled, in order to be able to extend them or to insert other
62
 
levels.<BR>
63
 
<BR>
64
 
 
65
 
 
66
 
The levels and their possible labels are not predefined. It depend on
67
 
how the syntax define them. To see which labels are defined and which
68
 
rule they contain, enter the toplevel and type for the normal syntax:
69
 
<PRE>
70
 
       #load "camlp4o.cma";;
71
 
       Grammar.Entry.print Pcaml.expr;; (* for the expressions *)
72
 
       Grammar.Entry.print Pcaml.patt;; (* for the patterns *)
73
 
                                        (* ... and so on *)
74
 
</PRE>
75
 
For the revised syntax, load <CODE>"camlp4r.cma"</CODE> instead. If you
76
 
defined another syntax of the whole language or want to see the other
77
 
syntaxes provided, load it before, and call <CODE>Grammar.Entry.print</CODE>
78
 
of the desired grammar entry. Look at the manual page
79
 
(<CODE>man camlp4</CODE> in the shell) to see all available syntaxes and
80
 
extensions.<BR>
81
 
<BR>
82
 
 
83
 
 
84
 
Once you have the list of the grammar entry you want to extend and the
85
 
possible level label, you can do your extension.<BR>
86
 
<BR>
87
 
 
88
 
 
89
 
<A NAME="toc49"></A><TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
90
 
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
91
 
<TR><TD><A NAME="htoc58"><B><FONT SIZE=5>7.2</FONT></B></A></TD>
92
 
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Example: ``repeat until'' like in Pascal</FONT></B></TD>
93
 
</TR></TABLE></DIV></TD>
94
 
</TR></TABLE><BR>
95
 
If you read all this tutorial, you are able to understand this
96
 
complete example. If you did not, just create the files and type the
97
 
indicated commands.<BR>
98
 
<BR>
99
 
 
100
 
 
101
 
Write first a file named <CODE>foo.ml</CODE> containing:
102
 
<PRE>
103
 
       open Pcaml;;
104
 
       EXTEND
105
 
         expr: LEVEL "expr1"
106
 
           [[ "repeat"; e1 = expr; "until"; e2 = expr -&gt;
107
 
                 &lt;:expr&lt; do { $e1$; while not $e2$ do { $e1$; } } &gt;&gt; ]];
108
 
       END;;
109
 
</PRE>
110
 
The compilation of this file can be done by typing under the shell
111
 
(the dollar is the shell prompt):
112
 
<PRE>
113
 
       $ ocamlc -pp "camlp4o pa_extend.cmo q_MLast.cmo" -I +camlp4 \
114
 
           -c foo.ml
115
 
</PRE>
116
 
Here is the file <CODE>bar.ml</CODE> containing a <CODE>repeat..until</CODE> statement:
117
 
<PRE>
118
 
       let main () =
119
 
         let i = ref 0 in
120
 
         repeat print_int !i; incr i until !i = 10;
121
 
         print_newline ()
122
 
       let _ = main ()
123
 
</PRE>
124
 
You can compile it by typing:
125
 
<PRE>
126
 
       $ ocamlc -pp "camlp4o ./foo.cmo" bar.ml
127
 
</PRE>
128
 
And run it:
129
 
<PRE>
130
 
       $ ./a.out
131
 
       0123456789
132
 
</PRE>
133
 
Or just pretty print the program with the expanded syntax:
134
 
<PRE>
135
 
       $ camlp4o ./foo.cmo pr_o.cmo bar.ml
136
 
       let main () =
137
 
         let i = ref 0 in
138
 
         begin
139
 
           begin print_int !i; incr i end;
140
 
           while not (!i = 10) do print_int !i; incr i done;
141
 
         end;
142
 
         print_newline ()
143
 
       ;;
144
 
       main ();;
145
 
</PRE>
146
 
<A NAME="toc50"></A><TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
147
 
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
148
 
<TR><TD><A NAME="htoc59"><B><FONT SIZE=5>7.3</FONT></B></A></TD>
149
 
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Example: a constant</FONT></B></TD>
150
 
</TR></TABLE></DIV></TD>
151
 
</TR></TABLE><BR>
152
 
If you want to have the equivalent of a <CODE>#define</CODE> of C, you can
153
 
write for example, if you want <CODE>FOO</CODE> to be replaced by <CODE>54</CODE>
154
 
in expressions and patterns:
155
 
<PRE>
156
 
       open Pcaml;;
157
 
       EXTEND
158
 
         expr: LEVEL "simple"
159
 
           [[ UIDENT "FOO" -&gt; &lt;:expr&lt; 54 &gt;&gt; ]];
160
 
         patt: LEVEL "simple"
161
 
           [[ UIDENT "FOO" -&gt; &lt;:patt&lt; 54 &gt;&gt; ]];
162
 
       END;;
163
 
</PRE>
164
 
The compilation of this file can be done by typing:
165
 
<PRE>
166
 
       $ ocamlc -pp "camlp4o pa_extend.cmo q_MLast.cmo" -I +camlp4 \
167
 
           -c foo.ml
168
 
</PRE>
169
 
Here is the file <CODE>bar.ml</CODE> containing <CODE>FOO</CODE> constants:
170
 
<PRE>
171
 
       FOO;;
172
 
       function FOO -&gt; 22;;
173
 
</PRE>
174
 
You can compile it by typing:
175
 
<PRE>
176
 
       $ ocamlc -pp "camlp4o ./foo.cmo" bar.ml
177
 
</PRE>
178
 
You can just pretty print the program with the expanded syntax:
179
 
<PRE>
180
 
       $ camlp4o ./foo.cmo pr_o.cmo bar.ml
181
 
       54;;
182
 
       function 54 -&gt; 22;;
183
 
</PRE>
184
 
<A NAME="toc51"></A><TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
185
 
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
186
 
<TR><TD><A NAME="htoc60"><B><FONT SIZE=5>7.4</FONT></B></A></TD>
187
 
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Example: a ``for'' loop like in C</FONT></B></TD>
188
 
</TR></TABLE></DIV></TD>
189
 
</TR></TABLE><BR>
190
 
Here is an example of an syntax extension allowing to write a ``for''
191
 
loop like in C. A construction is added with the loop variable and 3
192
 
parameters, simple expressions: the first one is the initial value,
193
 
the second the test, the third the way to change the loop variable.<BR>
194
 
<BR>
195
 
 
196
 
 
197
 
Note that we use here the directives <CODE>#load</CODE> inside the source of
198
 
the syntax extension, allowing to parse it with <CODE>camlp4o</CODE> without
199
 
having to specify these files in the command line.<BR>
200
 
<BR>
201
 
 
202
 
 
203
 
File ``cloop.ml'':
204
 
<PRE>
205
 
       #load "q_MLast.cmo";;
206
 
       #load "pa_extend.cmo";;
207
 
       
208
 
       open Pcaml
209
 
       
210
 
       let gensym =
211
 
         let cnt = ref 0 in
212
 
         fun var -&gt;
213
 
           let x = incr cnt; !cnt in
214
 
           var ^ "_gensym" ^ string_of_int x
215
 
       
216
 
       let gen_for loc v iv wh nx e =
217
 
         let loop_fun = gensym "iter" in
218
 
         &lt;:expr&lt;
219
 
           let rec $lid:loop_fun$ $lid:v$ =
220
 
             if $wh$ then do { $e$; $lid:loop_fun$ $nx$ } else ()
221
 
           in
222
 
           $lid:loop_fun$ $iv$ &gt;&gt;
223
 
       
224
 
       EXTEND
225
 
         expr: LEVEL "expr1"
226
 
           [ [ "for"; v = LIDENT; iv = expr LEVEL "simple";
227
 
               wh = expr LEVEL "simple"; nx = expr LEVEL "simple";
228
 
               "do"; e = expr; "done" -&gt;
229
 
                 gen_for loc v iv wh nx e ] ]
230
 
         ;
231
 
       END
232
 
</PRE>
233
 
Compile this file with:
234
 
<PRE>
235
 
       $ ocamlc -pp camlp4o -I +camlp4 -c cloop.ml
236
 
</PRE>
237
 
Example under the toplevel:
238
 
<PRE>
239
 
       $ ocaml
240
 
               Objective Caml version 3.02+7 (2001-09-29)
241
 
 
242
 
       # #load "camlp4o.cma";;
243
 
               Camlp4 Parsing version 3.02+7 (2001-09-29)
244
 
 
245
 
       # #load "cloop.cmo";;
246
 
       # for i = 0 to 10 do print_int i; done;; (* normal loop *)
247
 
       012345678910- : unit = ()
248
 
       # for c 0 (c&lt;10) (c+1) do print_int c; done;;
249
 
       0123456789- : unit = ()
250
 
       # for c 0 (c&lt;10) (c+3) do print_int c; done;;
251
 
       0369- : unit = ()
252
 
</PRE>
253
 
Exemple of compilation of a program using this construction:
254
 
<PRE>
255
 
       $ cat foo.ml
256
 
       for c 0 (c&lt;10) (c+2) do print_int c; done
257
 
       $ ocamlc -pp "camlp4o ./cloop.cmo" -c foo.ml
258
 
</PRE>
259
 
And if you want to see the generated program (for example to check
260
 
that the extension is correct):
261
 
<PRE>
262
 
       $ camlp4o ./cloop.cmo pr_o.cmo foo.ml
263
 
       let rec iter_gensym1 c =
264
 
         if c &lt; 10 then begin print_int c; iter_gensym1 (c + 2) end
265
 
       in
266
 
       iter_gensym1 0;;
267
 
</PRE>
268
 
<A NAME="toc52"></A><TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
269
 
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
270
 
<TR><TD><A NAME="htoc61"><B><FONT SIZE=5>7.5</FONT></B></A></TD>
271
 
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Example: generating printers of types</FONT></B></TD>
272
 
</TR></TABLE></DIV></TD>
273
 
</TR></TABLE><BR>
274
 
We are going to define a syntax extension, so that for all types
275
 
definitions, the definition of printers of the values of this types
276
 
is automatically added. In this example, we limit to sum types (types
277
 
with constructors), but it can be easily extensible for record types,
278
 
abstract types, types renaming.<BR>
279
 
<BR>
280
 
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
281
 
<TR><TD BGCOLOR="#7fff7f"><DIV ALIGN=center><TABLE>
282
 
<TR><TD><A NAME="htoc62"><B><FONT SIZE=4>7.5.1</FONT></B></A></TD>
283
 
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=4>First version: monomorphic sum types with constant constructors</FONT></B></TD>
284
 
</TR></TABLE></DIV></TD>
285
 
</TR></TABLE><BR>
286
 
The example, which is going to be our test, is the following file
287
 
``<CODE>col.ml</CODE>'':
288
 
<PRE>
289
 
       type colour = Red | Green | Blue
290
 
</PRE>
291
 
We want that, when preprocessed with the correct syntax extension,
292
 
this file be interpreted like this:
293
 
<PRE>
294
 
       type colour = Red | Green | Blue
295
 
       let print_colour =
296
 
         function
297
 
           Red -&gt; print_string "Red"
298
 
         | Green -&gt; print_string "Green"
299
 
         | Blue -&gt; print_string "Blue"
300
 
</PRE>
301
 
The syntax extension will be defined in the following file
302
 
``<CODE>pa_type.ml</CODE>''. As a beginning, let us just see how we insert
303
 
the grammar rule. The function ``<CODE>gen_print_funs</CODE>'' generating
304
 
the printer functions just generates a phony statement:
305
 
<PRE>
306
 
       #load "pa_extend.cmo";;
307
 
       #load "q_MLast.cmo";;
308
 
 
309
 
       let gen_print_funs loc tdl =
310
 
         &lt;:str_item&lt; not yet implemented &gt;&gt;
311
 
       
312
 
       let _ =
313
 
         EXTEND
314
 
           Pcaml.str_item:
315
 
             [ [ "type"; tdl = LIST1 Pcaml.type_declaration SEP "and" -&gt;
316
 
                   let si1 = &lt;:str_item&lt; type $list:tdl$ &gt;&gt; in
317
 
                   let si2 = gen_print_funs loc tdl in
318
 
                   &lt;:str_item&lt; declare $si1$; $si2$; end &gt;&gt; ] ]
319
 
           ;
320
 
         END
321
 
</PRE>
322
 
Remark the ``<CODE>declare</CODE>'' statement in the ``<CODE>str_item</CODE>''
323
 
syntax tree at the end of this file, destinated to group two structure
324
 
items together: 1/ the type definition 2/ the printer.<BR>
325
 
<BR>
326
 
 
327
 
 
328
 
This file can be compiled like this:
329
 
<PRE>
330
 
       $ ocamlc -pp camlp4o -I +camlp4 -c pa_type.ml
331
 
</PRE>
332
 
We can test the example file, ``<CODE>col.ml</CODE>'', but not yet with the
333
 
compiler, since it would generate semantic error because of the ``not
334
 
yet implemented'' statement. Let us test it therefore with a pretty
335
 
printer:
336
 
<PRE>
337
 
       $ camlp4o ./pa_type.cmo pr_o.cmo col.ml
338
 
       &lt;W&gt; Grammar extension: in [str_item], some rule has been masked
339
 
       type colour =
340
 
           Red
341
 
         | Green
342
 
         | Blue
343
 
       let _ = not yet implemented
344
 
</PRE>
345
 
See the extra generated statement ``not yet implemented''. You remark,
346
 
also, that there is a warning in the beginning: it means that the
347
 
syntax rule we added in <CODE>str_item</CODE> was already present in the
348
 
grammar we used.<BR>
349
 
<BR>
350
 
 
351
 
 
352
 
To avoid such a warning message, the solution is to add, before the
353
 
<CODE>EXTEND</CODE> statement, a <CODE>DELETE_RULE</CODE> statement:
354
 
<PRE>
355
 
       DELETE_RULE
356
 
         Pcaml.str_item: "type"; LIST1 Pcaml.type_declaration SEP "and"
357
 
       END;
358
 
</PRE>
359
 
Let us attack now the function <CODE>gen_print_funcs</CODE>. It receives a
360
 
list (since the ``<CODE>type</CODE>'' declaration can define several types,
361
 
possibly mutually recursive) of types definitions. We know that we
362
 
have to generate a definition, recursive, with as many printing
363
 
functions as types. The following function,
364
 
<CODE>gen_one_type_print_fun</CODE>, will generate the printer for one type
365
 
definition. For the moment, the body is a ``not yet implemented''
366
 
statement:
367
 
<PRE>
368
 
       let fun_name n = "print_" ^ n
369
 
 
370
 
       let gen_one_print_fun loc ((loc, n), tpl, tk, cl) =
371
 
         &lt;:patt&lt; $lid:fun_name n$ &gt;&gt;, &lt;:expr&lt; not yet implemented &gt;&gt;
372
 
 
373
 
       let gen_print_funs loc tdl =
374
 
         let pel = List.map (gen_one_print_fun loc) tdl in
375
 
         &lt;:str_item&lt; value rec $list:pel$ &gt;&gt;
376
 
</PRE>
377
 
Recompile the syntax expander file with these functions and test with
378
 
``<CODE>col.ml</CODE>'': you can see a function named ``<CODE>print_colour</CODE>''.<BR>
379
 
<BR>
380
 
 
381
 
 
382
 
Let use improve now ``<CODE>gen_one_print_fun</CODE>''. It has to generate a
383
 
let binding definition, composed of the couple of a pattern (the name
384
 
of the function) and an expression. Our function receives as parameter
385
 
a type definition which is a t-uple of 4 values: 1/ the type name
386
 
(with his location), 2/ the list of its possible parameters, 3/ the
387
 
type kind (a type, actually) and 4/ a list of possible constraints.<BR>
388
 
<BR>
389
 
 
390
 
 
391
 
In a first version, we are going to ignore the type parameters
392
 
``<CODE>tpl</CODE>'': we see later how they intervene in the generated
393
 
function and our code will work, for the moment, only for monomorphic
394
 
types.<BR>
395
 
<BR>
396
 
 
397
 
 
398
 
We limit also to the ``sum'' types (i.e. types with constructors); for
399
 
other types kinds, we shall generate a function which fails.<BR>
400
 
<BR>
401
 
 
402
 
 
403
 
We added the function ``<CODE>gen_print_sum</CODE>'' which treats a sum type
404
 
by generating a match association for each constructor (function
405
 
``<CODE>gen_print_cons</CODE>'') and building the function with the
406
 
resulting list.<BR>
407
 
<BR>
408
 
 
409
 
 
410
 
That function ``<CODE>gen_print_cons</CODE>'' gets a constructor definition,
411
 
i.e. a tuple with: 1/ a location, 2/ a string (the constructor name)
412
 
and 3/ a list of types parameters (ctyp list). We ignore for the
413
 
moments the constructors parameters. The function
414
 
``<CODE>gen_print_cons_patt</CODE>'' generates the pattern part of the case,
415
 
and ``<CODE>gen_print_cons_expr</CODE>'' the expression part of the
416
 
function, the print statement:<BR>
417
 
<BR>
418
 
 
419
 
 
420
 
Here is a first (but complete) version of our syntax extension (file
421
 
``<CODE>pa_type.ml</CODE>''):
422
 
<PRE>
423
 
       #load "pa_extend.cmo";;
424
 
       #load "q_MLast.cmo";;
425
 
 
426
 
       let fun_name n = "print_" ^ n
427
 
 
428
 
       let gen_print_cons_patt loc c tl =
429
 
         &lt;:patt&lt; $uid:c$ &gt;&gt;
430
 
 
431
 
       let gen_print_cons_expr loc c tl =
432
 
         &lt;:expr&lt; print_string $str:c$ &gt;&gt;
433
 
 
434
 
       let gen_print_cons (loc, c, tl) =
435
 
         let p = gen_print_cons_patt loc c tl in
436
 
         let e = gen_print_cons_expr loc c tl in
437
 
         p, None, e
438
 
 
439
 
       let gen_print_sum loc cdl =
440
 
         let pwel = List.map gen_print_cons cdl in
441
 
         &lt;:expr&lt; fun [ $list:pwel$ ] &gt;&gt;
442
 
 
443
 
       let gen_one_print_fun loc ((loc, n), tpl, tk, cl) =
444
 
         let body =
445
 
           match tk with
446
 
             &lt;:ctyp&lt; [ $list:cdl$ ] &gt;&gt; -&gt; gen_print_sum loc cdl
447
 
           | _ -&gt; &lt;:expr&lt; fun _ -&gt; failwith $str:fun_name n$ &gt;&gt;
448
 
         in
449
 
         &lt;:patt&lt; $lid:fun_name n$ &gt;&gt;, body
450
 
 
451
 
       let gen_print_funs loc tdl =
452
 
         let pel = List.map (gen_one_print_fun loc) tdl in
453
 
         &lt;:str_item&lt; value rec $list:pel$ &gt;&gt;
454
 
       
455
 
       let _ =
456
 
         DELETE_RULE
457
 
           Pcaml.str_item: "type"; LIST1 Pcaml.type_declaration SEP "and"
458
 
         END;
459
 
         EXTEND
460
 
           Pcaml.str_item:
461
 
             [ [ "type"; tdl = LIST1 Pcaml.type_declaration SEP "and" -&gt;
462
 
                   let si1 = &lt;:str_item&lt; type $list:tdl$ &gt;&gt; in
463
 
                   let si2 = gen_print_funs loc tdl in
464
 
                   &lt;:str_item&lt; declare $si1$; $si2$; end &gt;&gt; ] ]
465
 
           ;
466
 
         END
467
 
</PRE>
468
 
We can recompile this version, and test on the example file
469
 
``<CODE>col.ml</CODE>'' by pretty printing the result:
470
 
<PRE>
471
 
       $ ocamlc -pp camlp4o -I +camlp4 -c pa_type.ml
472
 
       $ camlp4o ./pa_type.cmo pr_o.cmo col.ml
473
 
       type colour =
474
 
           Red
475
 
         | Green
476
 
         | Blue
477
 
       let rec print_colour =
478
 
         function
479
 
           Red -&gt; print_string "Red"
480
 
         | Green -&gt; print_string "Green"
481
 
         | Blue -&gt; print_string "Blue"
482
 
</PRE>
483
 
It is what we wanted! This can be used, now, directly with the
484
 
compiler without the pretty printing phase:
485
 
<PRE>
486
 
       $ ocamlc -pp "camlp4o ./pa_type.cmo" -c col.ml
487
 
</PRE>
488
 
We could also add the directive ``<CODE>#load "./pa_type.cmo";;</CODE>'' in
489
 
the beginning of ``<CODE>col.ml</CODE>'' and just compile with:
490
 
<PRE>
491
 
       $ ocamlc -pp camlp4o -c col.ml
492
 
</PRE>
493
 
but it is not a good idea, since we may want to use the same source
494
 
with the preprocessing or without it.<BR>
495
 
<BR>
496
 
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
497
 
<TR><TD BGCOLOR="#7fff7f"><DIV ALIGN=center><TABLE>
498
 
<TR><TD><A NAME="htoc63"><B><FONT SIZE=4>7.5.2</FONT></B></A></TD>
499
 
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=4>Second version: constructors with parameters</FONT></B></TD>
500
 
</TR></TABLE></DIV></TD>
501
 
</TR></TABLE><BR>
502
 
Let us add the case of sum types having constructors with
503
 
parameters. Our example for testing that will be the definition of
504
 
lambda terms of section&nbsp;<A HREF="tutorial004.html#lambda terms">4.7</A>. File ``<CODE>term.ml</CODE>'':
505
 
<PRE>
506
 
        type term =
507
 
            Var of string
508
 
          | Func of string * term
509
 
          | Appl of term * term
510
 
</PRE>
511
 
The desired result should be something like this:
512
 
<PRE>
513
 
        type term =
514
 
            Var of string
515
 
          | Func of string * term
516
 
          | Appl of term * term
517
 
        let rec print_term =
518
 
          function
519
 
            Var x1 -&gt;
520
 
              print_string "Var"; print_string " ("; print_string x1;
521
 
              print_string ")"
522
 
          | Func (x1, x2) -&gt;
523
 
              print_string "Func"; print_string " ("; print_string x1
524
 
              print_string ", "; print_term x2; print_string ")"
525
 
          | Appl (x1, x2) -&gt;
526
 
              print_string "Appl"; print_string " ("; print_term x1
527
 
              print_string ", "; print_term x2; print_string ")"
528
 
</PRE>
529
 
Like in the above desired result, we decide to name the parameters
530
 
with ``<CODE>x</CODE>'' followed by the number of the parameter, defined by
531
 
the following function ``<CODE>param_name</CODE>'':
532
 
<PRE>
533
 
       let param_name cnt = "x" ^ string_of_int cnt
534
 
</PRE>
535
 
We need a function ``<CODE>list_mapi</CODE>'', which is like
536
 
``<CODE>List.map</CODE>'' but the function applied receives the number of
537
 
the list element as first parameter. This allows us to generate the
538
 
name of the constructor parameter while exploring the type list:
539
 
<PRE>
540
 
       let list_mapi f l =
541
 
         let rec loop cnt =
542
 
           function
543
 
             x :: l -&gt; f cnt x :: loop (cnt + 1) l
544
 
           | [] -&gt; []
545
 
         in
546
 
         loop 1 l
547
 
</PRE>
548
 
The function ``<CODE>gen_print_cons_patt</CODE>'' which treats the pattern
549
 
part of the match association, is changed like this:
550
 
<PRE>
551
 
       let gen_print_cons_patt loc c tl =
552
 
         let pl =
553
 
           list_mapi (fun n _ -&gt; &lt;:patt&lt; $lid:param_name n$ &gt;&gt;)
554
 
             tl
555
 
         in
556
 
         List.fold_left (fun p1 p2 -&gt; &lt;:patt&lt; $p1$ $p2$ &gt;&gt;)
557
 
           &lt;:patt&lt; $uid:c$ &gt;&gt; pl
558
 
</PRE>
559
 
With these changes, the pattern part of the generated function
560
 
``<CODE>print_term</CODE>'' is correct. Test it.<BR>
561
 
<BR>
562
 
 
563
 
 
564
 
For the expression part, we have to generate the call to the printers
565
 
for all the constructors parameters. We add a function
566
 
``<CODE>gen_print_type</CODE>'' to generate a printer associated with a
567
 
type. For the moment, it just generates it for a simple type name. For
568
 
other types, it generates a printer displaying an ellipsis:
569
 
<PRE>
570
 
       let gen_print_type loc =
571
 
         function
572
 
           &lt;:ctyp&lt; $lid:s$ &gt;&gt; -&gt; &lt;:expr&lt; $lid:fun_name s$ &gt;&gt;
573
 
         | _ -&gt; &lt;:expr&lt; fun _ -&gt; print_string "..." &gt;&gt;
574
 
</PRE>
575
 
We need also a function which generates the call to this printer
576
 
function with the constructor parameter:
577
 
<PRE>
578
 
       let gen_call loc n f = &lt;:expr&lt; $f$ $lid:param_name n$ &gt;&gt;
579
 
</PRE>
580
 
and a function adding the extra syntax: spaces, parentheses and
581
 
commas:
582
 
<PRE>
583
 
       let gen_print_con_extra_syntax loc el =
584
 
         let rec loop =
585
 
           function
586
 
             [] | [_] as e -&gt; e
587
 
           | e :: el -&gt; e :: &lt;:expr&lt; print_string ", " &gt;&gt; :: loop el
588
 
         in
589
 
         &lt;:expr&lt; print_string " (" &gt;&gt; :: loop el @
590
 
         [&lt;:expr&lt; print_string ")" &gt;&gt;]
591
 
</PRE>
592
 
Now, we can change the function ``<CODE>gen_print_cons_expr</CODE>'' using
593
 
all these functions:
594
 
<PRE>
595
 
       let gen_print_cons_expr loc c tl =
596
 
         let pr_con = &lt;:expr&lt; print_string $str:c$ &gt;&gt; in
597
 
         match tl with
598
 
           [] -&gt; pr_con
599
 
         | _ -&gt;
600
 
             let pr_params =
601
 
               let type_funs = List.map (gen_print_type loc) tl in
602
 
               list_mapi (gen_call loc) type_funs
603
 
             in
604
 
             let pr_all = gen_print_con_extra_syntax loc pr_params in
605
 
             let el = pr_con :: pr_all in
606
 
             &lt;:expr&lt; do { $list:el$ } &gt;&gt;
607
 
</PRE>
608
 
Grouping all these functions together, you can make a second version
609
 
of ``<CODE>pa_type.ml</CODE>'' which works with the file ``<CODE>term.ml</CODE>''.
610
 
Test it! Try it also with your own programs having sum type definitions.<BR>
611
 
<BR>
612
 
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
613
 
<TR><TD BGCOLOR="#7fff7f"><DIV ALIGN=center><TABLE>
614
 
<TR><TD><A NAME="htoc64"><B><FONT SIZE=4>7.5.3</FONT></B></A></TD>
615
 
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=4>Third version: polymorphic types</FONT></B></TD>
616
 
</TR></TABLE></DIV></TD>
617
 
</TR></TABLE><BR>
618
 
This time, we are going to generate the good code for polymorphic
619
 
types, i.e. types defined with types variables. Our example will be
620
 
the definition of the type ``<CODE>mlist</CODE>'' like this. File
621
 
``<CODE>mlist.ml</CODE>'':
622
 
<PRE>
623
 
       type 'a mlist = Nil | Cons of 'a * 'a mlist
624
 
</PRE>
625
 
The printer of such a type will receive as parameter the print
626
 
functions of the instantiated type. As many as the type has type
627
 
variables. We can then call ``<CODE>print_mlist</CODE>
628
 
<CODE>print_int</CODE>'' for an ``<CODE>int mlist</CODE>'', ``<CODE>print_mlist</CODE>
629
 
<CODE>print_string</CODE>'' for a ``<CODE>string mlist</CODE>'' and so on.<BR>
630
 
<BR>
631
 
 
632
 
 
633
 
The desired result for the type ``<CODE>mlist</CODE>'' is:
634
 
<PRE>
635
 
       type 'a mlist = Nil | Cons of 'a * 'a mlist
636
 
       let rec print_mlist pr_a =
637
 
         function
638
 
           Nil -&gt; print_string "Nil"
639
 
         | Cons (x1, x2) -&gt;
640
 
             print_string "Cons"; print_string " ("; pr_a x1;
641
 
             print_string ", "; print_mlist pr_a x2; print_string ")"
642
 
</PRE>
643
 
The name of the printer function for a type variable will be
644
 
``<CODE>pr_</CODE>'' followed by the type variable name:
645
 
<PRE>
646
 
       let fun_param_name n = "pr_" ^ n
647
 
</PRE>
648
 
To add the function parameters to the printer definition (``<CODE>let</CODE>
649
 
<CODE>print_mlist</CODE> <CODE>pr_a</CODE> <CODE>= ...</CODE>'' in our example), we
650
 
change our function ``<CODE>gen_one_print_func</CODE>'' by inserting them in
651
 
the body of the function, just before its result, like this:
652
 
<PRE>
653
 
         let body =
654
 
           List.fold_right
655
 
             (fun (v, _) e -&gt;
656
 
                &lt;:expr&lt; fun $lid:fun_param_name v$ -&gt; $e$ &gt;&gt;)
657
 
             tpl body
658
 
         in
659
 
</PRE>
660
 
For the printing of a type variable (``<CODE>pr_a</CODE> <CODE>x1</CODE>'' in our
661
 
example), we add the case of type variables in our function
662
 
``<CODE>gen_print_type</CODE>'':
663
 
<PRE>
664
 
         | &lt;:ctyp&lt; '$s$ &gt;&gt; -&gt; &lt;:expr&lt; $lid:fun_param_name s$ &gt;&gt;
665
 
</PRE>
666
 
And to generate the printing of types with parameters (we have a
667
 
recursive case in our example: ``<CODE>print_mlist</CODE> <CODE>pr_a</CODE>
668
 
<CODE>x2</CODE>'' for the constructor parameter of type ``<CODE>'a</CODE>
669
 
<CODE>mlist</CODE>''), we add, in the same function, the case of types
670
 
applications. But since it needs a recursive call, the function
671
 
``<CODE>gen_print_type</CODE>'' is rewritten with a internal recursive
672
 
definition.<BR>
673
 
<BR>
674
 
 
675
 
 
676
 
Here is the complete version:
677
 
<PRE>
678
 
       #load "pa_extend.cmo";;
679
 
       #load "q_MLast.cmo";;
680
 
 
681
 
       let fun_name n = "print_" ^ n
682
 
       let fun_param_name n = "pr_" ^ n
683
 
       let param_name cnt = "x" ^ string_of_int cnt
684
 
 
685
 
       let list_mapi f l =
686
 
         let rec loop cnt =
687
 
           function
688
 
             x :: l -&gt; f cnt x :: loop (cnt + 1) l
689
 
           | [] -&gt; []
690
 
         in
691
 
         loop 1 l
692
 
 
693
 
       let gen_print_type loc t =
694
 
         let rec eot =
695
 
           function
696
 
             &lt;:ctyp&lt; $t1$ $t2$ &gt;&gt; -&gt; &lt;:expr&lt; $eot t1$ $eot t2$ &gt;&gt;
697
 
           | &lt;:ctyp&lt; $lid:s$ &gt;&gt; -&gt; &lt;:expr&lt; $lid:fun_name s$ &gt;&gt;
698
 
           | &lt;:ctyp&lt; '$s$ &gt;&gt; -&gt; &lt;:expr&lt; $lid:fun_param_name s$ &gt;&gt;
699
 
           | _ -&gt; &lt;:expr&lt; fun _ -&gt; print_string "..." &gt;&gt;
700
 
         in
701
 
         eot t
702
 
 
703
 
       let gen_call loc n f = &lt;:expr&lt; $f$ $lid:param_name n$ &gt;&gt;
704
 
 
705
 
       let gen_print_cons_patt loc c tl =
706
 
         let pl =
707
 
           list_mapi (fun n _ -&gt; &lt;:patt&lt; $lid:param_name n$ &gt;&gt;)
708
 
             tl
709
 
         in
710
 
         List.fold_left (fun p1 p2 -&gt; &lt;:patt&lt; $p1$ $p2$ &gt;&gt;)
711
 
           &lt;:patt&lt; $uid:c$ &gt;&gt; pl
712
 
 
713
 
       let gen_print_con_extra_syntax loc el =
714
 
         let rec loop =
715
 
           function
716
 
             [] | [_] as e -&gt; e
717
 
           | e :: el -&gt; e :: &lt;:expr&lt; print_string ", " &gt;&gt; :: loop el
718
 
         in
719
 
         &lt;:expr&lt; print_string " (" &gt;&gt; :: loop el @
720
 
         [&lt;:expr&lt; print_string ")" &gt;&gt;]
721
 
 
722
 
       let gen_print_cons_expr loc c tl =
723
 
         let pr_con = &lt;:expr&lt; print_string $str:c$ &gt;&gt; in
724
 
         match tl with
725
 
           [] -&gt; pr_con
726
 
         | _ -&gt;
727
 
             let pr_params =
728
 
               let type_funs = List.map (gen_print_type loc) tl in
729
 
               list_mapi (gen_call loc) type_funs
730
 
             in
731
 
             let pr_all = gen_print_con_extra_syntax loc pr_params in
732
 
             let el = pr_con :: pr_all in
733
 
             &lt;:expr&lt; do { $list:el$ } &gt;&gt;
734
 
 
735
 
       let gen_print_cons (loc, c, tl) =
736
 
         let p = gen_print_cons_patt loc c tl in
737
 
         let e = gen_print_cons_expr loc c tl in
738
 
         p, None, e
739
 
 
740
 
       let gen_print_sum loc cdl =
741
 
         let pwel = List.map gen_print_cons cdl in
742
 
         &lt;:expr&lt; fun [ $list:pwel$ ] &gt;&gt;
743
 
 
744
 
       let gen_one_print_fun loc ((loc, n), tpl, tk, cl) =
745
 
         let body =
746
 
           match tk with
747
 
             &lt;:ctyp&lt; [ $list:cdl$ ] &gt;&gt; -&gt; gen_print_sum loc cdl
748
 
           | _ -&gt; &lt;:expr&lt; fun _ -&gt; failwith $str:fun_name n$ &gt;&gt;
749
 
         in
750
 
         let body =
751
 
           List.fold_right
752
 
             (fun (v, _) e -&gt;
753
 
                &lt;:expr&lt; fun $lid:fun_param_name v$ -&gt; $e$ &gt;&gt;)
754
 
             tpl body
755
 
         in
756
 
         &lt;:patt&lt; $lid:fun_name n$ &gt;&gt;, body
757
 
 
758
 
       let gen_print_funs loc tdl =
759
 
         let pel = List.map (gen_one_print_fun loc) tdl in
760
 
         &lt;:str_item&lt; value rec $list:pel$ &gt;&gt;
761
 
       
762
 
       let _ =
763
 
         DELETE_RULE
764
 
           Pcaml.str_item: "type"; LIST1 Pcaml.type_declaration SEP "and"
765
 
         END;
766
 
         EXTEND
767
 
           Pcaml.str_item:
768
 
             [ [ "type"; tdl = LIST1 Pcaml.type_declaration SEP "and" -&gt;
769
 
                   let si1 = &lt;:str_item&lt; type $list:tdl$ &gt;&gt; in
770
 
                   let si2 = gen_print_funs loc tdl in
771
 
                   &lt;:str_item&lt; declare $si1$; $si2$; end &gt;&gt; ] ]
772
 
           ;
773
 
         END
774
 
</PRE>
775
 
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
776
 
<TR><TD BGCOLOR="#7fff7f"><DIV ALIGN=center><TABLE>
777
 
<TR><TD><A NAME="htoc65"><B><FONT SIZE=4>7.5.4</FONT></B></A></TD>
778
 
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=4>Improvements</FONT></B></TD>
779
 
</TR></TABLE></DIV></TD>
780
 
</TR></TABLE><BR>
781
 
It is possible to add, the same way, the other kind of types: record
782
 
types, abstract types, and so on.<BR>
783
 
<BR>
784
 
 
785
 
 
786
 
Another interesting improvement is to generate, instead of
787
 
``<CODE>print_string</CODE>'' statements, functions of the
788
 
``<CODE>Format</CODE>'' library, with pretty printing boxes.<BR>
789
 
<BR>
790
 
 
791
 
 
792
 
Further, that version can be still improved, by generating only one
793
 
``<CODE>Format.fprintf</CODE>'' by printing case (instead of a sequence of
794
 
printing statements), using the very useful abbreviations provided by
795
 
that library by the prefixes ``<CODE>@</CODE>'' inside the format strings.
796
 
<BR>
797
 
<BR>
798
 
<I><FONT COLOR=maroon>
799
 
<br>
800
 
For remarks about Camlp4, write to:
801
 
<img src="http://cristal.inria.fr/~ddr/images/email.jpg" alt=email align=top>
802
 
</FONT></I><HR>
803
 
<A HREF="tutorial006.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
804
 
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Up"></A>
805
 
<A HREF="tutorial008.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
806
 
</BODY>
807
 
</HTML>