Changeset 33547 in project


Ignore:
Timestamp:
07/28/16 12:55:37 (4 years ago)
Author:
juergen
Message:

procedural-macros 2.0 docu

File:
1 edited

Legend:

Unmodified
Added
Removed
  • wiki/eggref/4/procedural-macros

    r33077 r33547  
    4242sym ... denote the injected symbols to break hygiene (if there is none,
    4343the constructed macro is hygienic). key ... and pat .... symbols are
    44 as in syntax-rules, fender ... are expressions on pattern variables
    45 which must pass for the pattern to match, and tpl .... are usually
    46 quasiquoted expressions.
     44as in syntax-rules, fender ... are pairs of pattern variables and
     45predicates, the latter applied to the former must be true for the
     46pattern to match, and tpl .... are usually quasiquoted expressions.
    4747
    4848And here is the syntax of define-macro
     
    5353macro-rules.
    5454
    55 The implementation of these macros relies heavily on two routines of
    56 Paul Graham's macro bible "On Lisp, p. 232", which he used to implement
    57 dbind, a variant of Common Lisp's destructuring-bind. They are called
    58 destruc and dbind-ex and evaluated at compile-time. Here is a Scheme
    59 version for lists only:
    60 
    61 <enscript highlight=scheme>
    62 (define (destruc pat seq)
    63   (let loop ((pat pat) (seq seq) (n 0))
    64     (if (pair? pat)
    65       (let ((p (car pat)) (recu (loop (cdr pat) seq (+ n 1))))
    66         (if (symbol? p)
    67           (cons `(,p (list-ref ,seq ,n)) recu)
    68           (let ((g (gensym)))
    69             (cons (cons `(,g (list-ref ,seq ,n))
    70                         (loop p g 0))
    71                   recu))))
    72       (let ((tail `(list-tail ,seq ,n)))
    73         (if (null? pat)
    74           '()
    75           `((,pat ,tail)))))))
    76 (define (dbind-ex binds body)
    77   (if (null? binds)
    78     `(begin ,@body)
    79     `(let ,(map (lambda (b) (if (pair? (car b)) (car b) b))
    80                 binds)
    81        ,(dbind-ex
    82           (mappend (lambda (b) (if (pair? (car b)) (cdr b) '()))
    83                    binds)
    84           body))))
    85 (define (mappend fn lists)
    86   (apply append (map fn lists)))
    87 </enscript>
    88 
    89 Graham's code works as follows: First, destruc traverses the pattern and
    90 groups each symbol with the location of a runtime object, using gensyms
    91 to step down the pattern while grouping the gensym bound object with all
    92 pairs depending on this gensym. So, for example,
    93 
    94 <enscript highlight=scheme>
    95 (destruc '(a (b . c) . d) 'seq)
    96 </enscript>
    97 
    98 will result in
    99 
    100 <enscript highlight=scheme>
    101 ((a (list-ref seq 0))
    102  ((#:g (list-ref seq 1)) (b (list-ref #:g 0)) (c (list-tail #:g 1)))
    103  (d (list-tail seq 2)))
    104 </enscript>
    105 
    106 This tree is then transformed via dbind-ex into a nested let to produce
    107 dbind's result
    108 
    109 <enscript highlight=scheme>
    110 (let ((a (list-ref seq 0))
    111       (#:g (list-ref seq 1))
    112       (d (list-tail seq 2)))
    113   (let ((b (list-ref #:g 0))
    114         (c (list-tail #:g 1)))
    115     body))
    116 </enscript>
    117  
    118 Contrary to the bindings library, this library doesn't use generic
    119 sequences. Indeed, for macro-writing macros lists are sufficient, I
    120 think. But off course, I have to provide some extensions to Graham's
    121 code, length checks and non-symbol literals, as in the bindings
    122 egg; but contrary to that egg, wildcards are omitted, out of hygiene
    123 reasons. Nonsymbol literals bind nothing but match only to themselfs.
    124 
    125 The last feature missing is fenders, which is important in particular
    126 for macro-rules and can easily be implemented with a where clause: A
    127 pattern matches successfully if only each pattern variable can be bound,
    128 the length checks pass, the literals match themselfs and the where
    129 clause is satisfied. If any of those conditions is hurt, the next
    130 pattern is tried.
     55The implementation of these macros depends on the bind-case macro of the
     56bindings package which does the pattern matching of macro-rules. Since
     57the former can handle wildcards, non-symbol literals and fenders, so
     58does the latter.
    13159
    13260=== The module procedural-macros
     
    14977checking a pattern variable, var, against a sequence of predicates.
    15078
    151 Note, that non-symbol literals are accepted in each pat and
    152 considered a match if they are equal to the corresponding expression in
    153 the macro-code. The same applies to fenders: If they are not passed, the
     79Note, that non-symbol literals are accepted in each pat and considered a
     80match if they are equal to the corresponding expression in the
     81macro-code. The same applies to fenders: If they are not passed, the
    15482pattern is not matched.
    15583
     
    183111once-only must be imported for-syntax.
    184112
     113==== define-ir-macro-transformer
     114
     115<macro>(define-er-macro-transformer (name form inject compare?)</macro>
     116
     117wrapper around ir-macro-transformer.
     118
     119==== define-er-macro-transformer
     120
     121<macro>(define-er-macro-transformer (name form rename compare?)</macro>
     122
     123wrapper around er-macro-transformer.
     124
     125==== with-mapped-symbols
     126
     127<macro>(with-mapped-symbols mapper prefix- (prefix-x ....) xpr ....)</macro>
     128
     129binds a series of prefixed names, prefix-x ....
     130to the images of the original names, x ...., under mapper
     131and evaluates xpr .... in this context
     132
    185133==== with-gensyms
    186134
    187 <macro>(with-gensyms (x ...) . body)</macro>
    188 
    189 to be used in a macro body. Generates a list of gensyms x ...
    190 with-gensyms must be imported for-syntax.
     135<macro>(with-gensyms (x ...) xpr ....)</macro>
     136
     137to be used in a macro body and hence to be imported for-syntax.
     138Generates a list of gensyms x ... which can be used in xpr .....
     139
    191140
    192141=== Requirements
    193142
    194 None
     143bindings, basic-sequences
    195144
    196145=== Usage
    197146
    198147<enscript highlight=scheme>
     148
    199149(use procedural-macros)
     150
     151(import-for-syntax
     152 (only procedural-macros macro-rules once-only
     153                         with-mapped-symbols with-gensyms)
     154
    200155(import-for-syntax (only procedural-macros macro-rules with-gensyms once-only))
    201156</enscript>
     
    204159
    205160<enscript highlight=scheme>
     161
     162(use procedural-macros)
     163
     164(import-for-syntax (only procedural-macros macro-rules once-only)
     165                   (only data-structures list-of?))
    206166
    207167(use procedural-macros)
     
    343303== Last update
    344304
    345 Jan 11, 2016
     305Jul 28, 2016
    346306
    347307== Author
     
    381341
    382342== Version History
     343; 2.0 : New implementation based on bind-case from the bindings egg
    383344; 1.1 : fenders now writen in the form (var ok? ...) accepting zero or many predicates 
    384345; 1.0.3 : wildcards ommitted, out of hygiene reasons
Note: See TracChangeset for help on using the changeset viewer.