Here is how I would write it (if I wrote something like that):
First, we need a helper function that replaces one syntax object wherever an identifier occurs in another syntax object. Note. never use syntax->datum for what you intend to consider as an expression (or which contains expressions or definitions, etc.). Instead, recursively deploy using syntax-e and, after processing, return it together as before:
(require (for-syntax racket/base)) (begin-for-syntax ;; syntax-substitute : Syntax Identifier Syntax -> Syntax ;; Replace id with replacement everywhere in stx. (define (syntax-substitute stx id replacement) (let loop ([stx stx]) (cond [(and (identifier? stx) (bound-identifier=? stx id)) replacement] [(syntax? stx) (datum->syntax stx (loop (syntax-e stx)) stx stx)] ;; Unwrapped data cases: [(pair? stx) (cons (loop (car stx)) (loop (cdr stx)))] ;; FIXME: also traverse vectors, etc? [else stx]))))
Use bound-identifier=? when you implement a binding-like relationship, such as a replacement. (This is a rare case, usually free-identifier=? - the correct comparison to use.)
Now the macro simply interprets for-clause, performs the substitution, and collects the results. If you really want the term list to be substituted into the compilation time expression, use syntax-local-eval from racket/syntax .
(require (for-syntax racket/syntax)) (define-syntax (macro-for stx) (syntax-case stx () [(_ ([i ct-sequence]) body) (with-syntax ([(replaced-body ...) (for/list ([replacement (syntax-local-eval
In this example, use:
> (macro-for ([i '(1 2 3)]) (printf "The value of ~s is now ~s.\n" 'ii)) The value of 1 is now 1. The value of 2 is now 2. The value of 3 is now 3.
Note that it replaces the appearance of i in quotation marks, so you do not see the i character in the output. Is that what you expect?
Disclaimer: This is not common with typical Racket macros. It’s usually a bad idea to go look for and replace in unexpanded forms, and usually there are more idiomatic ways to achieve what you want.
source share