source: project/wiki/man/5/Module (chicken syntax) @ 35529

Last change on this file since 35529 was 35529, checked in by felix winkelmann, 2 years ago

man/5: corrections, added shit, [re]moved shit

File size: 16.3 KB
Line 
1[[tags: manual]]
2[[toc:]]
3
4== Module (chicken syntax)
5
6This module has support for syntax- and module handling. This module
7is used by default, unless a program is compiled with the
8{{-explicit-use}} option.
9
10=== Macro transformers
11
12Macro transformers are procedures you can use in a {{define-syntax}}
13context to register a procedure that can transform s-expressions into
14other s-expressions.  Only use these when you need to break hygiene in
15a controlled way; for many use cases {{syntax-rules}} is more
16appropriate, as it offers stronger guarantees of hygiene, is more
17high-level and is standard R5RS Scheme.
18
19For those situations where you need more control, however, CHICKEN
20supports two kinds of low-level macros: so-called explicit renaming
21and implicit renaming macros.
22
23==== Explicit renaming macros
24
25The low-level macro facility that CHICKEN provides is called "explicit
26renaming" and allows writing hygienic or non-hygienic macros
27procedurally.  When given a the return value of the one of the
28procedures {{er-macro-transformer}} or {{ir-macro-transformer}}
29instead of a {{syntax-rules}} form, {{define-syntax}} evaluates the
30procedure in a distinct expansion environment (initially having access
31to the exported identifiers of the {{scheme}} module). The procedure
32takes an expression and two other arguments and returns a transformed
33expression.
34
35For example, the transformation procedure for a {{call}} macro such
36that {{(call proc arg ...)}} expands into {{(proc arg ...)}} can be
37written as
38
39  (er-macro-transformer
40    (lambda (exp rename compare)
41      (cdr exp)))
42
43Expressions are represented as lists in the traditional manner,
44except that identifiers are represented as special uninterned symbols.
45
46The second argument to a transformation procedure is a renaming procedure that
47takes the representation of an identifier as its argument and returns the
48representation of a fresh identifier that occurs nowhere else in the
49program.  For example, the transformation procedure for a simplified
50version of the {{let}} macro might be written as
51
52  (er-macro-transformer
53    (lambda (exp rename compare)
54      (let ((vars (map car (cadr exp)))
55            (inits (map cadr (cadr exp)))
56            (body (cddr exp)))
57        `((lambda ,vars ,@body)
58          ,@inits))))
59
60This would not be hygienic, however.  A hygienic {{let}} macro must
61rename the identifier {{lambda}} to protect it from being captured by
62a local binding.  The renaming effectively creates a fresh alias for
63{{lambda}}, one that cannot be captured by any subsequent binding:
64
65  (er-macro-transformer
66    (lambda (exp rename compare)
67      (let ((vars (map car (cadr exp)))
68            (inits (map cadr (cadr exp)))
69            (body (cddr exp)))
70        `((,(rename 'lambda) ,vars ,@body)
71          ,@inits))))
72
73The expression returned by the transformation procedure will be
74expanded in the syntactic environment obtained from the syntactic
75environment of the macro application by binding any fresh identifiers
76generated by the renaming procedure to the denotations of the original
77identifiers in the syntactic environment in which the macro was
78defined.  This means that a renamed identifier will denote the same
79thing as the original identifier unless the transformation procedure
80that renamed the identifier placed an occurrence of it in a binding
81position.
82
83Identifiers obtained from any two calls to the renaming procedure with
84the same argument will necessarily be the same, but will denote the
85same syntactical binding. It is an error if the renaming procedure is
86called after the transformation procedure has returned.
87
88The third argument to a transformation procedure is a comparison
89predicate that takes the representations of two identifiers as its
90arguments and returns true if and only if they denote the same thing
91in the syntactic environment that will be used to expand the
92transformed macro application.  For example, the transformation
93procedure for a simplified version of the {{cond}} macro can be written
94as
95
96  (er-macro-transformer
97    (lambda (exp rename compare)
98      (let ((clauses (cdr exp)))
99        (if (null? clauses)
100            `(,(rename 'quote) unspecified)
101            (let* ((first (car clauses))
102                   (rest (cdr clauses))
103                   (test (car first)))
104              (cond ((and (symbol? test)
105                          (compare test (rename 'else)))
106                     `(,(rename 'begin) ,@(cdr first)))
107                    (else `(,(rename 'if)
108                            ,test
109                             (,(rename 'begin) ,@(cdr first))
110                             (,(r 'cond) ,@rest)))))))))
111
112In this example the identifier {{else}} is renamed before being passed
113to the comparison predicate, so the comparison will be true if and
114only if the test expression is an identifier that denotes the same
115thing in the syntactic environment of the expression being transformed
116as {{else}} denotes in the syntactic environment in which the {{cond}}
117macro was defined.  If {{else}} were not renamed before being passed to
118the comparison predicate, then it would match a local variable that
119happened to be named {{else}}, and the macro would not be hygienic.
120The final recursive call to {{cond}} also needs to be renamed because
121someone might create an alias for this macro and use it in a {{let}}
122where {{cond}} is an ordinary variable.
123
124Some macros are non-hygienic by design.  For example, the
125following defines a {{loop}} macro that implicitly binds {{exit}} to an
126escape procedure.  The binding of {{exit}} is intended to capture free
127references to {{exit}} in the body of the loop, so {{exit}} is not
128renamed.
129
130  (define-syntax loop
131    (er-macro-transformer
132      (lambda (x r c)
133        (let ((body (cdr x)))
134          `(,(r 'call-with-current-continuation)
135            (,(r 'lambda) (exit)
136             (,(r 'let) ,(r 'f) () ,@body (,(r 'f)))))))))
137
138Suppose a {{while}} macro is implemented using {{loop}}, with the intent
139that {{exit}} may be used to escape from the {{while}} loop.  The {{while}}
140macro cannot be written as
141
142  (define-syntax while
143    (syntax-rules ()
144      ((while test body ...)
145       (loop (if (not test) (exit #f))
146             body ...))))
147
148because the reference to {{exit}} that is inserted by the {{while}} macro
149is intended to be captured by the binding of {{exit}} that will be
150inserted by the {{loop}} macro.  In other words, this {{while}} macro is
151not hygienic.  Like {{loop}}, it must be written using procedurally:
152
153  (define-syntax while
154    (er-macro-transformer
155      (lambda (x r c)
156        (let ((test (cadr x))
157              (body (cddr x)))
158          `(,(r 'loop)
159            (,(r 'if) (,(r 'not) ,test) (exit #f))
160            ,@body)))))
161
162Think about it: If we ''did'' rename {{exit}}, it would refer to an
163{{exit}} procedure existing in the context of the macro's definition.
164That one [[Unit library#exit|actually exists]]; it is the procedure
165that exits the Scheme interpreter.  Definitely ''not'' the one we want :)
166So now we make it refer to an {{exit}} that's locally bound in the
167environment where the macro is expanded.
168
169Note: this implementation of explicit-renaming macros allows passing
170arbitrary expressions to the renaming and comparison procedures. When
171being renamed, a fresh copy of the expression will be produced, with all
172identifiers renamed appropriately. Comparison also supports arbitrary
173expressions as arguments.
174
175
176===== er-macro-transformer
177
178<procedure>(er-macro-transformer TRANSFORMER)</procedure>
179
180Returns an explicit-renaming macro transformer procedure created from
181the procedural macro body {{TRANSFORMER}}, which is a procedure of
182three arguments.
183
184This procedure will be called on expansion with the complete
185s-expression of the macro invocation, a rename procedure that
186hygienically renames identifiers and a comparison procedure that
187compares (possibly renamed) identifiers (see the section "Explicit
188renaming macros" below for a detailed explanation on non-R5RS macros).
189
190Implementation note: this procedure currently just returns its
191argument unchanged and is available for writing low-level macros in a
192more portable fashion, without hard-coding the signature of a
193transformer procedure.
194
195=== Implicit renaming macros
196
197Explicit renaming macros generally require the user to perform quite a
198few renames, because most identifiers that aren't taken from the input
199expression should generally be inserted hygienically.  It would make
200more sense to give the output expression as-is, and only explicitly
201convert those identifiers that you want to treat as ''unhygienic''.
202
203This can be done with implicit renaming macros.  They just swap the
204default insertion "mode" from unhygienic to hygienic, so to speak.
205Here's the {{cond}} example from the previous section as an ir-macro:
206
207
208  (ir-macro-transformer
209    (lambda (exp inject compare)
210      (let ((clauses (cdr exp)))
211        (if (null? clauses)
212            `(quote unspecified)
213            (let* ((first (car clauses))
214                   (rest (cdr clauses))
215                   (test (car first)))
216              (cond ((and (symbol? test)
217                          (compare test 'else))
218                     `(begin ,@(cdr first)))
219                    (else `(if ,test
220                               (begin ,@(cdr first))
221                               (cond ,@rest)))))))))
222
223In this example the identifier {{else}} does ''not'' need to be renamed
224before being passed to the comparison predicate because it is already
225''implicitly'' renamed.  This comparison will also be true if and
226only if the test expression is an identifier that denotes the same
227thing in the syntactic environment of the expression being transformed
228as {{else}} denotes in the syntactic environment in which the {{cond}}
229macro was defined.  If {{else}} were not renamed before being passed to
230the comparison predicate, then it would match a local variable that
231happened to be named {{else}}, and the macro would not be hygienic.
232
233As you can see, the code is a lot clearer because it isn't obscured
234by excessive renaming.
235
236Here's the {{loop}} macro so you can see how hygiene can be broken
237with implicit renaming macros:
238
239  (define-syntax loop
240    (ir-macro-transformer
241      (lambda (expr inject compare)
242        (let ((body (cdr expr)))
243          `(call-with-current-continuation
244            (lambda (,(inject 'exit))
245             (let f () ,@body (f))))))))
246
247The {{while}} macro is a little trickier: do we inject the call to
248{{exit}} or not?  Just like the explicit renaming macro version
249did ''not'' rename it, we must inject it to allow it to be captured
250by the {{loop}} macro:
251
252  (define-syntax while
253    (ir-macro-transformer
254      (lambda (expr inject compare)
255        (let ((test (cadr expr))
256              (body (cddr expr)))
257          `(loop
258            (if (not ,test) (,(inject 'exit) #f))
259            ,@body)))))
260
261Note: Just like explicit renaming macros, this implementation of
262implicit renaming macros allow passing arbitrary expressions to
263the injection and comparison procedures.  The injection procedure
264also return fresh copies of its input.
265
266
267===== ir-macro-transformer
268
269<procedure>(ir-macro-transformer TRANSFORMER)</procedure>
270
271This procedure accepts a ''reverse'' syntax transformer, also known as
272an ''implicit renaming macro transformer''.  This is a transformer which
273works almost like er-macro-transformer, except the rename and compare
274procedures it receives work a little differently.
275
276The rename procedure is now called {{inject}} and instead of renaming
277the identifier to be resolved in the macro's definition environment,
278it will explicitly ''inject'' the identifier to be resolved in the
279expansion environment.  Any non-injected identifiers in the output
280expression produced by the transformer will be implicitly renamed to
281refer to the macro's environment instead.  All identifiers in the
282input expression are of course implicitly injected just like with
283explicit renaming macros.  See the section above for a more complete
284explanation.
285
286To compare an input identifier you can generally compare to the bare
287symbol and only free identifiers will match.  In practice, this means
288that when you would call e.g.  {{(compare (cadr expression) (rename
289'x))}} in an ER macro, you simply call {{(compare (cadr expression)
290'x)}} in the IR macro.  Likewise, an ''unhygienic'' ER macro's
291comparison {{(compare sym 'abc)}} should be written as {{(compare sym
292(inject 'abc))}} in an IR macro.
293
294
295=== Expanding macros
296
297==== expand
298
299<procedure>(expand X)</procedure>
300
301If {{X}} is a macro-form, expand the macro (and repeat expansion
302until expression is a non-macro form).  Returns the resulting expression.
303
304=== Macro helper procedures
305
306==== begin-for-syntax
307
308<macro>(begin-for-syntax EXP ...)</macro>
309
310Equivalent to {{(begin EXP ...)}}, but performs the evaluation of the
311expression during macro-expansion time, using the macro environment
312rather than the interaction environment.
313
314You can use this to define your own helper procedures that you can
315call from a syntax transformer.
316
317==== define-for-syntax
318
319<macro>(define-for-syntax (NAME VAR ...) EXP1 ...)</macro><br>
320<macro>(define-for-syntax (NAME VAR1 ... VARn . VARn+1) EXP1 ...)</macro><br>
321<macro>(define-for-syntax NAME [VALUE])</macro>
322
323Defines the toplevel variable {{NAME}} at macro-expansion time. This
324can be helpful when you want to define support procedures for use in
325macro-transformers, for example.
326
327Essentially, this is a shorthand for
328{{(begin-for-syntax (define ...))}}.
329
330Note that {{define-for-syntax}} definitions within a module are
331implicitly added to that module's import library. Refer to the
332documentation on [[Modules#import-libraries|import libraries]]
333for more information.
334
335
336==== syntax
337
338<procedure>(syntax EXPRESSION)</procedure>
339
340This will quote the {{EXPRESSION}} for use in a syntax expansion.  Any
341syntactic information will be stripped from the {{EXPRESSION}}.
342
343
344==== strip-syntax
345
346<procedure>(strip-syntax EXPRESSION)</procedure>
347
348Strips all syntactical information from {{EXPRESSION}}, returning a
349new expression where symbols have all context-information removed.
350
351You should use this procedure whenever you want to manually construct
352new identifiers, which an unhygienic macro can insert.  In some cases
353it does not ''appear'' to be necessary to strip context information
354when you use the macro, but you still should do it.  Sometimes
355identifiers will not have been renamed (most often at toplevel), but
356there may be other contexts in which identifiers ''will'' have been
357renamed.
358
359
360==== get-line-number
361
362<procedure>(get-line-number EXPR)</procedure>
363
364If {{EXPR}} is a pair with the car being a symbol, and line-number
365information is available for this expression, then this procedure
366returns the associated source file and line number as a string. If
367line-number information is not available, then {{#f}} is returned.
368Note that line-number information for expressions is only available in
369the compiler.
370
371==== syntax-error
372
373<procedure>(syntax-error [LOCATION] MESSAGE ARGUMENT ...)</procedure>
374
375Signals an exception of the kind {{(exn syntax)}}. Otherwise identical
376to {{error}}.
377
378
379=== Compiler macros
380
381==== define-compiler-syntax
382
383<macro>(define-compiler-syntax NAME)</macro><br>
384<macro>(define-compiler-syntax NAME TRANSFORMER)</macro><br>
385
386Defines what is usually called a ''compiler macro'' in Lisp: {{NAME}}
387should be the name of a globally or locally bound procedure. Any
388direct call to this procedure will be transformed before compilation,
389which allows arbitrary rewritings of function calls.
390
391{{TRANSFORMER}} can be a {{syntax-rules}} expression or a transformer
392procedure (as returned by {{er-macro-transformer}} or
393{{ir-macro-transformer}}). Returning the original form in an
394explicit/implicit-renaming macro or simply "falling trough" all
395patterns in a {{syntax-rules}} form will keep the original expression
396and compile it normally.
397
398In the interpreter this form does nothing and returns an unspecified
399value.
400
401Compiler-syntax is always local to the current compilation unit and
402can not be exported. Compiler-syntax defined inside a module is not
403visible outside of that module.
404
405{{define-compiler-syntax}} should only be used at top-level. Local
406compiler-syntax can be defined with {{let-compiler-syntax}}.
407
408<enscript highlight=scheme>
409(define-compiler-syntax +
410  (syntax-rules ()
411    ((_) 1)
412    ((_ x 0) x) ) )
413</enscript>
414
415If no transformer is given, then {{(define-compiler-syntax NAME)}}
416removes any compiler-syntax definitions for {{NAME}}.
417
418
419==== let-compiler-syntax
420
421<macro>(let-compiler-syntax ((NAME [TRANSFORMER]) ...) BODY ...)</macro>
422
423Allows definition local compiler macros, which are only applicable
424inside {{BODY ...}}.  By not providing a {{TRANSFORMER}} expression,
425compiler-syntax for specific identifiers can be temporarily disabled.
426
427---
428Previous: [[Module (chicken string)]]
429
430Next: [[Module (chicken tcp)]]
Note: See TracBrowser for help on using the repository browser.