Changeset 38045 in project


Ignore:
Timestamp:
01/01/20 18:36:18 (3 months ago)
Author:
juergen
Message:

procedural-macros 2.0 docu

File:
1 edited

Legend:

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

    r37896 r38045  
    1515limitations but are tedious to use.
    1616
    17 First, you must care to avoid variable capture with renaming, if you
     17First, you must care to avoid variable capture with renaming if you
    1818want hygienic macros, or you must decide which variables should be
    1919captured on purpose. Implicit renaming here helps a lot: You simply
     
    2323Second, you must do the destructuring of the macro code by hand.
    2424Wouldn't it be nice, if this could be done automatically behind the
    25 scene as well?
    26 
    27 This library provides the means for this to happen in the form of two
    28 modules, basic-macros and procedural-macros. The latter exports the
    29 symbols of the former as well, so that in general only the latter is
    30 needed.
    31 
    32 === Module basic-macros
    33 
    34 Usually an ambituous explicit renaming macro contains a long let
    35 defining the renamed symbols -- usually prefixed with some fixed symbol
    36 constant like % -- which is then executed in the macro's body by
    37 unquoting it. Our two macros create the let automatically. The only
    38 thing you have to do is providing a prefix and using it to prefix all
    39 symbols you want renamed resp injected.
    40 
    41 Here is a simple example, the numeric if.
    42 
    43 <enscript highlight=scheme>
    44   (define-er-macro (nif form % compare?)
    45     (bind (_ xpr pos zer neg) form
    46       `(,%let ((,%result ,xpr))
    47          (,%cond
    48            ((,%positive? ,%result) ,pos)
    49            ((,%negative? ,%result) ,neg)
    50            (,%else ,zer)))))
    51 </enscript>
    52 
    53 Note, that one of the standard arguments of an er-macro-transformer,
    54 rename, is replaced by the rename-prefix %, which characterize the
    55 symbols in the body to be renamed.
    56 
    57 The macro searches its body for symbols starting with this prefix,
    58 collects them in a list, removes duplicates and adds the necesary let
    59 with pairs of the form
    60 
    61   (%name (rename 'name)
    62 
    63 to the front of the body. In other words it does what you usually do by
    64 hand.
    65 
    66 For implicit renaming macros the list of injected symbols is usually,
    67 but not allways, short, even empty for nif. Of course, the generated let
    68 replaces rename with inject in this case.
    69 For example, here is a version of alambda, an anaphoric version of
    70 lambda, which injects the name self:
    71 
    72 <enscript highlight=scheme>
    73   (define-ir-macro (alambda form % compare?)
    74     (bind (_ args xpr . xprs) form
    75       `(letrec ((,%self (lambda ,args ,xpr ,@xprs)))
    76          ,%self)))
    77 </enscript>
    78 
    79 ==== basic-macros
    80 
    81 <procedure>(basic-macros sym ..)</procedure>
    82 
    83 documentation procedure
    84 
    85 ==== define-syntax-rule
    86 
    87 <macro>(define-syntax-rule (name . args) xpr . xprs)</macro>
    88 <macro>(define-syntax-rule (name . args) (keywords . keys) xpr .  xprs)</macro>
    89 
    90 simplyfied version of syntax-rules if there is only one rule.
    91 
    92 ==== define-ir-macro-transformer
    93 
    94 <macro>(define-er-macro-transformer (name form inject compare?)</macro>
    95 
    96 wrapper around ir-macro-transformer.
    97 
    98 ==== define-er-macro-transformer
    99 
    100 <macro>(define-er-macro-transformer (name form rename compare?)</macro>
    101 
    102 wrapper around er-macro-transformer.
    103 
    104 ==== define-er-macro
    105 
    106 <macro>(define-er-macro (name form rename-symbol compare?) xpr . xprs)</macro>
    107 
    108 defines an explicit-renaming-macro name with macro-code form renaming
    109 each symbol in the body xpr . xprs starting with rename-symbol
    110 automatically.
    111 
    112 ==== define-ir-macro
    113 
    114 <macro>(define-ir-macro (name form inject-symbol compare?) xpr . xprs)</macro>
    115 
    116 defines an implicit-renaming-macro name with macro-code form injecting
    117 each symbol in the body xpr . xprs starting with inject-symbol
    118 automatically.
    119 
    120 ==== once-only
    121 
    122 <macro>(once-only (x . xs) xpr . xprs)</macro>
    123 
    124 to be used in a macro-body to avoid side-effects.
    125 The arguments x . xs are only evaluated once.
    126 once-only must be used for-syntax in explicit or implicit renaming
    127 macros.
    128 
    129 ==== with-mapped-symbols
    130 
    131 <macro>(with-mapped-symbols mapper prefix- (prefix-x ...) xpr . xprs)</macro>
    132 
    133 binds a series of prefixed names, prefix-x ...
    134 to the images of the original names, x ..., under mapper
    135 and evaluates xpr . xprs in this context.
    136 To be used for-synax in ir- or er-macro-transformers, where mapper is
    137 either inject or rename.
    138 
    139 ==== with-gensyms
    140 
    141 <macro>(with-gensyms (x ...) xpr ....)</macro>
    142 
    143 to be used in a macro body and hence to be imported for-syntax.
    144 Generates a list of gensyms x ... which can be used in xpr .....
     25scene as well?  Well, two macros of the bindings egg, bind and bind-case,
     26will help here.
     27
     28This library provides the means for this to happen. In particular,
     29you'll find a variant of good old define-macro and a macro, macro-rules,
     30which looks much like syntax-rules.
    14531
    14632
    14733=== Module procedural-macros
    14834
    149 Combining implicit renaming with destructuring, some macro-writing
    150 macros are defined, in particular, a (mostly) hygienic procedural
    151 define-macro and a procedural version of syntax-rules, named
    152 macro-rules. The latter is almost as easy to use as syntax-rules, but
    153 much more powerfull. Here is its syntax
    154 
    155 <macro>(macro-rules sym ... (key ...) (pat (where fender ...) .. tpl) ....)</macro>
    156 
    157 Note the special use of dots here and below: Three dots are ellipses, as
    158 usual, i.e. the pattern on the left is repeated zero or more times, two
    159 dots, zero or one time, 4 dots one ore several times.
    160 
    161 This form can be used instead of syntax-rules in define-syntax,
    162 let-sytax and letrec-syntax, provided, you use it for-syntax.
    163 sym ... denote the injected symbols to break hygiene (if there is none,
    164 the constructed macro is hygienic). key ... and pat .... symbols are
    165 as in syntax-rules, fender ... are pairs of pattern variables and
    166 predicates, the latter applied to the former must be true for the
    167 pattern to match, and tpl .... are usually quasiquoted expressions.
    168 
    169 And here is the syntax of define-macro
    170 
    171 <macro>(define-macro (name . args) (where (x . xs) ...) .. xpr ....)</macro>
    172 
    173 The implementation of these macros depends on the bind-case macro of the
    174 basic-macros package which does the pattern matching of macro-rules. Since
    175 the former can handle wildcards, non-symbol literals and fenders, so
    176 does the latter.
    177 
    178 ==== procedural-macros
    179 
    180 <procedure>(procedural-macros sym ..)</procedure>
    181 
    182 documentation procedure. Shows the exported symbols and the syntax of
    183 such an exported symbol, respectively.
    184 
    18535==== macro-rules
    18636
    187 <macro>(macro-rules sym ... (keyword ...) (pat (where fender ...) .. tpl) ....)</macro>
     37<macro>(macro-rules sym ... (key ...) (pat tpl) ....)</macro>
    18838
    18939like syntax-rules, but the templates are usually quasiquote-expressions.
    19040Moreover, the symbols sym ... are injected, if there are any.
    191 Here and in the sequel, fender is an expresseion of the form
    192  (var ok?  ...)
    193 checking a pattern variable, var, against a sequence of predicates.
    19441
    19542Note, that non-symbol literals are accepted in each pat and considered a
    19643match if they are equal to the corresponding expression in the
    197 macro-code. The same applies to fenders: If they are not passed, the
    198 pattern is not matched.
    199 
    200 macro-rules must be used for-syntax if used in the preprocessing
     44macro-code. The keys are transformed to keyword literals behind the
     45scene.
     46
     47macro-rules must be imported for syntax if used in the preprocessing
    20148phase of a macro evaluation.
    20249
    20350==== define-macro
    20451
    205 <macro>(define-macro (name . args) (where (x . xs) ...) .. xpr ....))</macro>
    206 
    207 where xs is either a list of predicates, providing fenders,
    208 or a singleton with one of the symbols keyword or injection,
    209 providing keyword parameters or unhygienic macros.
    210 Generates a hygienic implicit-renaming macro, name, if no injection
    211 parameter is given.
     52<macro>(define-macro (name . args)
     53         (with-explicit-renaming (c? %x ...) xpr ....))</macro>
     54<macro>(define-macro (name . args)
     55         (with-implicit-renaming (c? %x ...) xpr ....))</macro>
     56<macro>(define-macro (name . args) xpr ....)</macro>
     57
     58defines explicit- or implicit-renaming macros with body xpr ....
     59c? is a compare-routine to handle keys and %x ... are renamed or
     60injected symbols to be used in the body.
     61
     62The last form is implicit-renaming without injections and keys.
    21263
    21364==== macro-let
    21465
    215 <macro>(macro-let (((name . args) (where fender ...) .. xpr ...) ...) body ....)</macro>
    216 
    217 evaluates body ... in the context of parallel hygienic macros name ....
     66<macro>(macro-let (((name . args) xpr ...) ...) xpr ....)</macro>
     67
     68evaluates xpr .... in the context of parallel hygienic macros name ...
    21869
    21970==== macro-letrec
    22071
    221 <macro>(macro-letrec (((name . args) (where fender ...) .. xpr ...) ...) body ....)</macro>
    222 
    223 evaluates body ... in the context of recursive hygienic macros name ....
    224 
    225 === Reexports from basic-macros
     72<macro>(macro-letrec (((name . args) xpr ...) ...) xpr ....)</macro>
     73
     74evaluates xpr .... in the context of recursive hygienic macros name ...
    22675
    22776==== once-only
     
    23382once-only must be imported for-syntax.
    23483
    235 ==== define-ir-macro-transformer
    236 
    237 <macro>(define-er-macro-transformer (name form inject compare?)</macro>
    238 
    239 wrapper around ir-macro-transformer.
    240 
    241 ==== define-er-macro-transformer
    242 
    243 <macro>(define-er-macro-transformer (name form rename compare?)</macro>
    244 
    245 wrapper around er-macro-transformer.
    246 
    247 ==== define-er-macro
    248 
    249 <macro>(define-er-macro (name form rename-symbol compare?) xpr . xprs)</macro>
    250 
    251 defines an explicit-renaming-macro name with macro-code form renaming
    252 each symbol in the body xpr . xprs starting with rename-symbol
    253 automatically.
    254 
    255 ==== define-ir-macro
    256 
    257 <macro>(define-ir-macro (name form inject-symbol compare?) xpr . xprs)</macro>
    258 
    259 defines an implicit-renaming-macro name with macro-code form injecting
    260 each symbol in the body xpr . xprs starting with inject-symbol
    261 automatically.
    262 
    263 ==== with-mapped-symbols
    264 
    265 <macro>(with-mapped-symbols mapper prefix- (prefix-x ....) xpr ....)</macro>
    266 
    267 binds a series of prefixed names, prefix-x ....
    268 to the images of the original names, x ...., under mapper
    269 and evaluates xpr .... in this context
     84==== with-renamed-symbols
     85
     86<macro>(with-renamed-symbols (renamer %x ....) xpr ....)</macro>
     87
     88binds a series of prefixed names, %x ....
     89to the images of the original names, x ...., under renamer
     90and evaluates xpr .... in this context.
     91The prefix is arbitrary, but must be only one letter.
     92The macro must be imported for syntax.
    27093
    27194==== with-gensyms
     
    27598to be used in a macro body and hence to be imported for-syntax.
    27699Generates a list of gensyms x ... which can be used in xpr .....
     100The macro must be imported for syntax.
     101
     102==== procedural-macros
     103
     104<procedure>(procedural-macros sym ..)</procedure>
     105
     106documentation procedure. Shows the exported symbols and the syntax of
     107such an exported symbol, respectively.
    277108
    278109
     
    289120(import-for-syntax
    290121 (only procedural-macros macro-rules once-only
    291                          with-mapped-symbols with-gensyms)
     122                         with-renamed-symbols with-gensyms)
    292123
    293124</enscript>
     
    299130(import procedural-macros)
    300131(import-for-syntax
     132  (only checks >>)
    301133  (only bindings bind bind-case)
    302   (only procedural-macros macro-rules with-mapped-symbols once-only)
    303   (only (chicken base) list-of?))
    304 
    305 (define-er-macro (Square form % compare?)
    306   (let ((x (cadr form)))
    307     (once-only (x)
    308       `(* ,x ,x))))
    309 
    310 (define-er-macro-transformer (Swap! form rename compare?)
    311   (let ((x (cadr form)) (y (caddr form)))
    312     (with-mapped-symbols rename % (%tmp %let %set!)
    313       `(,%let ((,%tmp ,x))
    314          (,%set! ,x ,y)
    315          (,%set! ,y ,%tmp)))))
    316 
    317 (define-er-macro (Nif form % compare?)
    318   (bind (_ xpr pos zer neg)
    319     form
    320     `(,%let ((,%result ,xpr))
    321             (,%cond
    322               ((,%positive? ,%result) ,pos)
    323               ((,%negative? ,%result) ,neg)
    324               (,%else ,zer)))))
    325 
    326 (define-ir-macro (Vif form % compare?)
    327   (bind-case form
    328     ((_ test (key xpr . xprs))
    329      (cond
    330        ((compare? key %then)
    331         `(if ,test (begin ,xpr ,@xprs)))
    332        ((compare? key %else)
    333         `(if ,(not test) (begin ,xpr ,@xprs)))
    334        (else
    335          `(error 'Vif "syntax-error"))))
    336     ((_ test (key1 xpr . xprs) (key2 ypr . yprs))
    337      (cond
    338        ((and (compare? key1 %then)
    339              (compare? key2 %else))
    340        `(if ,test
    341           (begin ,xpr ,@xprs)
    342           (begin ,ypr ,@yprs)))
    343        ((and (compare? key1 %else)
    344              (compare? key2 %then))
    345        `(if ,test
    346           (begin ,ypr ,@yprs)
    347           (begin ,xpr ,@xprs)))
    348        (else
    349          `(error 'Vif "syntax-error"))))
    350     ))
    351 
    352 ;; two anaphoric macros
     134  (only procedural-macros macro-rules with-renamed-symbols once-only))
     135
     136;; TWO ANAPHORIC MACROS
    353137(define-syntax aif
    354138  (macro-rules it ()
     
    360144        (if ,it ,consequent ,alternative)))))
    361145
    362 (define-macro (alambda args xpr . xprs)
    363   (self injection)
    364   `(letrec ((,self (lambda ,args ,xpr ,@xprs)))
    365      ,self))
    366 
    367 ;; effective membership testing
    368 (define-macro (in? what equ? . choices)
     146(define-syntax alambda
     147  (macro-rules self ()
     148    ((_ args xpr . xprs)
     149     `(letrec ((,self (lambda ,args ,xpr ,@xprs)))
     150        ,self))))
     151
     152;; EFFICIENT MEMBERSHIP TESTING
     153(define-macro (in what equ? . choices)
    369154  (let ((insym 'in))
    370155    `(let ((,insym ,what))
     
    372157                  choices)))))
    373158
    374 ;; verbose if
     159;; FOR WITH ONCE-ONLY
     160(define-macro (for (var start end) xpr . xprs)
     161  (once-only (start end)
     162    `(do ((,var ,start (add1 ,var)))
     163       ((= ,var ,end))
     164       ,xpr ,@xprs)))
     165
     166;; VERBOSE IF
    375167(define-syntax vif
    376168  (macro-rules (then else)
     
    386178        (begin ,ypr ,@yprs)))))
    387179
    388 ;; procedural version of cond
     180;; PROCEDURAL VERSION OF COND
    389181(define-syntax my-cond
    390182  (macro-rules (else =>)
     
    392184     `(begin ,xpr ,@xprs))
    393185    ((_ (test => xpr))
    394      (let ((temp test))
    395        `(if ,temp (,xpr ,temp))))
     186     `(let ((tmp ,test))
     187        (if tmp (,xpr tmp))))
    396188    ((_ (test => xpr) . clauses)
    397      (let ((temp test))
    398        `(if ,temp
    399           (,xpr ,temp)
     189     `(let ((tmp ,test))
     190        (if tmp
     191          (,xpr tmp)
    400192          (my-cond ,@clauses))))
    401     ((_ (test)) `(if #f #f))
     193    ((_ (test))
     194     ;`(if #f #f))
     195     test)
    402196    ((_ (test) . clauses)
    403      (let ((temp test))
    404        `(if ,temp
    405           ,temp
     197     `(let ((tmp ,test))
     198        (if tmp
     199          tmp
    406200          (my-cond ,@clauses))))
    407201    ((_ (test xpr . xprs))
     
    410204     `(if ,test
    411205        (begin ,xpr ,@xprs)
    412         (my-cond ,@clauses)))))
    413 
    414 ;; procedural version of letrec
    415 (define-macro (my-letrec var-val-pairs . body)
    416   (where (var-val-pairs (list-of? pair?)))
    417   (let ((vars (map car var-val-pairs))
    418         (vals (map cadr var-val-pairs))
    419         (aux (map (lambda (x) (gensym)) var-val-pairs)))
     206        (my-cond ,@clauses)))
     207    ))
     208
     209;; PROCEDURAL VERSION OF LETREC
     210(define-macro (my-letrec pairs xpr . xprs)
     211  (>> pairs (list-of? pair?))
     212  (let ((vars (map car pairs))
     213        (vals (map cadr pairs))
     214        (aux (map (lambda (x) (gensym)) pairs)))
    420215    `(let ,(map (lambda (var) `(,var #f)) vars)
    421216       (let ,(map (lambda (a v) `(,a ,v)) aux vals)
    422217         ,@(map (lambda (v e) `(set! ,v ,e)) vars vals)
    423          ,@body))))
    424 
    425 (my-letrec ((o? (lambda (m) (if (zero? m) #f (e? (- m 1)))))
    426             (e? (lambda (n) (if (zero? n) #t (o? (- n 1))))))
    427            (list (o? 95) (e? 95)))
    428 
    429 ;; local macros
    430 (letrec-syntax (
    431      (sec (macro-rules ()
    432                ((_ lst) `(car (res ,lst)))))
    433      (res (macro-rules ()
    434              ((_ lst) `(cdr ,lst))))
    435      )
    436      (sec '(1 2 3)))
    437 ;-> 2
    438 
    439 (macro-letrec (
    440      ((sec lst) `(car (res ,lst)))
    441      ((res lst) `(cdr ,lst))
    442      )
    443      (sec '(1 2 3)))
    444 ;-> 2
    445 
    446 (macro-let (
    447      ((fir lst) (where (lst list?)) `(car ,lst))
    448      ((res lst) (where (lst list?)) `(cdr ,lst))
    449      )
    450      (fir (res '(1 2 3))))
    451 ;-> 2
    452 
    453 ;; non-symbolic literals
     218         ,xpr ,@xprs))))
     219
     220;; NON-SYMBOLIC LITERALS
    454221(define-syntax foo
    455222  (macro-rules ()
    456223    ((_ "foo" x) x)
    457     ((_ #f x) x)
    458     ((_ a b) (where (a string?)) `(list ,a ,b))
    459     ((_ a b) (where (a odd?)) `(list ,a ,b))
     224    ((_ #f x) `(list 'false))
     225    ((_ #f x) 'false)
     226    ((_ a b) (>> a string?) `(list ,a ,b))
     227    ((_ a b) (>> a odd?) `(list ,a ,b))
    460228    ((_ a b) a)))
    461 (foo "foo" 1)
    462 ; -> 1
    463 (foo "bar" 2)
    464 ; -> '("bar" 2)
    465 (foo #f 'blabla)
    466 ; -> 'blabla
    467 (foo 1 2)
    468 ; -> '(1 2)
    469 (foo 2 3)
    470 ; -> 2
    471 
    472 (define-syntax add
    473   (macro-rules ()
    474     ((_ x y) (where (x string?) (y string?))
    475      `(string-append ,x ,y))
    476     (( _ x y) (where (x integer?) (y integer?))
    477      `(+ ,x ,y))))
    478 (add 1 2)
    479 ;-> 3
    480 (add "x" "y")
    481 ;-> "xy"
     229
     230;; LOCAL MACROS
     231(macro-let (
     232  ((first lst)
     233   `(begin
     234      (>> ,lst list?)
     235      (car ,lst)))
     236  ((rest lst)
     237   `(begin
     238      (>> ,lst list?)
     239      (cdr ,lst)))
     240  )
     241  (first (rest '(1 2 3))))
     242
     243(macro-letrec (
     244  ((second lst) `(car (rest ,lst)))
     245  ((rest lst) `(cdr ,lst))
     246  )
     247  (second '(1 2 3)))
     248
    482249</enscript>
    483250
    484251== Last update
    485252
    486 Sep 21, 2019
     253Jan 1, 2020
    487254
    488255== Author
     
    492259== License
    493260
    494  Copyright (c) 2015-2019, Juergen Lorenz
     261 Copyright (c) 2015-2020, Juergen Lorenz
    495262 All rights reserved.
    496263
     
    523290== Version History
    524291
    525 ; 1.1 fixed some bugs reported by Diego. I thank him.
     292; 2.0 : simplyfied and streamlined rewrite. Only one module remains.
     293; 1.1 : fixed some bugs reported by Diego. I thank him.
    526294; 1.0.1 : port from chicken-4 procedural- and basic-macros
Note: See TracChangeset for help on using the changeset viewer.