Dear Racket list,<br><br>As a non-expert of Scheme macro system,<br>I&#39;ve been struggling for a while to find out how to <br>define a macro that can take a procedure as argument.<br><br>For example, suppose you want to define a macro that takes<br>


an identifier and an expression, modifies the identifier in some <br>
way, and defines this new identifier with the expression.<br>
And suppose you want the identifier modification to be generic,<br>
i.e. the macro should take as argument a procedure that tells<br>
how to build the new identifier.<br>
Here is a way to do it (see below).<br>
<br>Maybe this is a well known technique, maybe there is a <br>better way to do it, or maybe this is straightforward to experts ;<br>but I couldn&#39;t find it on Google or in different books, and since<br>that took me some time I thought this could help others.<br>

Any comment is welcome (some of my own comments might<br>even be wrong).<br><br><br>#lang racket<br><br>#|<br>This tutorial shows how to create a generic variable definer,<br>that can take a procedure as argument to build the id name.<br>

|#<br><br>;; First, we create a simple macro that modifies the identifier name.<br>;;<br>;; (datum-&gt;syntax #&#39;var new-id-expr ....) makes the new-id visible<br>;; in the same context where the id held by var is used (here, <br>

;; at the call to define-me).<br>;; See datum-&gt;syntax for more information.<br>(define-syntax (define-me stx)<br>  (syntax-case stx ()<br>    [(_ var val)<br>     (with-syntax ([id (datum-&gt;syntax <br>                        #&#39;var<br>

                        (string-&gt;symbol<br>                         (string-append <br>                          (symbol-&gt;string (syntax-&gt;datum #&#39;var))<br>                          &quot;-me&quot;))<br>                        #&#39;var #&#39;var #&#39;var)])<br>

       #&#39;(define id val))]))<br><br>(define-me a 1)<br>a-me<br><br>;; Second, we would like the building of the new id to be modifiable,<br>;; without having to rewrite the entire macro.<br>;; We would like to take another argument to define-me,<br>

;; but this is not possible in a straightforward way,<br>;; because such arguments can only be syntax objects, and not generic code.<br>;;<br>;; So, instead we create a macro maker to abstract the relevant part,<br>;; and call that macro maker to instantiate the desired specific macro.<br>

;; Then we can use that new macro to define the variable.<br>(define-syntax-rule (define-define-me define-me id-maker)<br>  (define-syntax (define-me stx)<br>    (syntax-case stx ()<br>      [(_ var val)<br>       (with-syntax ([id (datum-&gt;syntax <br>

                          #&#39;var<br>                          (string-&gt;symbol<br>                           (id-maker<br>                            (symbol-&gt;string (syntax-&gt;datum #&#39;var))<br>                            ))<br>

                          #&#39;var #&#39;var #&#39;var)])<br>         #&#39;(define id val))])))<br><br>; Instantiate a macro for a specific id-maker.<br>(define-define-me define-me2 (ë(id-str)(string-append id-str &quot;-me2&quot;)))<br>

<br>(define-me2 a 2)<br>a-me2<br><br>;; Third, we incorporate the macro call to define-me2 into the macro maker.<br>;; <br>;; The intermediate macro, however defined at the top level,<br>;; is only &quot;temporary&quot;, because its name (define-me) is<br>

;; completely internal to the surrounding macro, thus hygiene hides it.<br>;; This also means that the surrounding macro can be used several<br>;; times without interfering with itself.<br>;;<br>;; Note that inside define-me, var must be taken from the call<br>

;; to define-me, and not directly from define-me-proc arguments,<br>;; so that datum-&gt;syntax can create the new id for runtime,<br>;; on the contrary to id-maker which is used at compile time.<br>(define-syntax-rule (define-me-proc id-maker var val)<br>

  (begin<br>    (define-syntax (define-me stx)<br>      (syntax-case stx ()<br>        [(_ var val)<br>         (with-syntax ([id (datum-&gt;syntax <br>                            #&#39;var<br>                            (string-&gt;symbol<br>

                             (id-maker<br>                              (symbol-&gt;string (syntax-&gt;datum #&#39;var))<br>                              ))<br>                            #&#39;var #&#39;var #&#39;var)])<br>

           #&#39;(define id val))]))<br>    (define-me var val)<br>    ))<br>  <br>  <br>(define-me-proc (ë(id-str)(string-append id-str &quot;-me3&quot;))<br>  a 3)<br><br>a-me3<br><br>; We can also define a helper, as long as it is defined for-syntax,<br>

; since it is called inside the define-me internal macro, <br>; which is at syntax-level.<br>(define-for-syntax (id-maker id-str)<br>  (string-append id-str &quot;-me3-also&quot;))<br><br>(define-me-proc id-maker<br>  a &#39;3-also)<br>

<br>a-me3-also<br><br><br>-- <br>Laurent<br>