2

I'm trying to capture the expanded forms by defining my own module-begin:

(define-syntax-rule (my-module-begin e ...)
  (#%module-begin            
   e ...
  (foo e ...)))

Am I correct that foo here gets the original forms? If so is there a way for foo to get the expanded forms instead?

JRR
  • 6,014
  • 6
  • 39
  • 59

1 Answers1

2

To get the expanded forms you'll need to use local-expand in some way.

Part 1, an incomplete solution

You might think to call local-expand separately on every expression like this:

#lang racket

(require syntax/parse/define
         (for-syntax syntax/stx))

(define-simple-macro (my-module-begin e ...)
  ; define a function that expands it
  #:do [(define (expand/mod-ctx e)
          (local-expand e 'module '()))]
  ; get the expanded versions by calling that function on the e's
  #:with (e-expanded ...) (stx-map expand/mod-ctx #'(e ...))
  ; use the expanded versions inside foo
  (#%module-begin            
   e-expanded ...
   (foo e-expanded ...)))

This works when the e forms are expressions like (+ 1 2) or (let ([x 3] [y 4]) (make-list x y)). However, it doesn't work when the e forms can be definitions.

Part 2, getting the expanded versions from Racket's #%module-begin

One way to support using local-expand with these module-level definitions is to wrap it in racket's #%module-begin form before expanding. This allows it to process all the es together in one call to local-expand.

(define-simple-macro (my-module-begin e ...)
  ; get the expanded versions by calling that function on a
  ; *constructed* module-begin form
  #:with (_ e-expanded ...) (local-expand #'(#%module-begin e ...) 'module-begin '())
  ; use the expanded versions inside foo
  (#%module-begin            
   e-expanded ...
   (foo e-expanded ...)))

This gets Racket's #%module-begin to handle the definitions, and when it's done, you can pattern match on it with (_ e-expanded ...).

Alex Knauth
  • 8,133
  • 2
  • 16
  • 31