[plt-scheme] make-module macro

From: Ryan Culpepper (ryan_sml at yahoo.com)
Date: Tue Jan 17 13:48:23 EST 2006

--- wayne at taxupdate.com wrote:

> I'd like to do this in a macro:
> 
> (begin
>   (module test mzscheme
>     (provide (all-defined))
>     (define (testf) (display "worked\n")))
>   (require (prefix test. test))
>   
> Testing with:
> 
> (test.testf) 
> 
> produces:
> 
> worked
>   
> Here's my attempt:
> 
> (define-syntax (make-module stx)
>   (syntax-case stx ()
>    ((make-module module-name expr ...)
>     (with-syntax ((dotted-id
>                    (datum->syntax-object
> 		    (syntax make-module)
> 		    (string->symbol
> 		     (string-append
> 		      (symbol->string
>  		       (syntax-object->datum (syntax module-name)))
> 		       ".")))))
>      #`(begin
>         (module module-name mzscheme
> 	 (provide (all-defined))
> 	 expr ...
> 	 )
> 	(require (prefix dotted-id module-name)))))))

This is an interaction between the hygienic macro expander and the
require form. Since the require form is the result of a macro
expansion, it has a mark on it. Executing a marked require binds
identifiers *with the same mark(s)*, so you cannot refer to testf
with an *unmarked* identifier.

You can see this illustrated with the following code (add it after
your macro definition):

  (require (planet "syntax-browser.ss" ("ryanc" "syntax-browser.plt"
1)))

  (define stx
    #'(make-module test
        (define (testf) (display 'ok))
        (display "test ran\n")))
  (browse-syntaxes (list stx (expand-once stx) #'test.testf))

This will show you the original code (in black), then the result of
expanding the use of your make-module macro, then the identifier you
were trying to use to access the module's testf export.

Notice that the require form that you produce is in red. Try changing
your macro to this:

(define-syntax (make-module stx)
  (syntax-case stx ()
   ((make-module module-name expr ...)
    (with-syntax ((dotted-id
                   (datum->syntax-object
		    (syntax make-module)
		    (string->symbol
		     (string-append
		      (symbol->string
 		       (syntax-object->datum (syntax module-name)))
		       ".")))))
     #`(begin
        (module module-name mzscheme
	 (provide (all-defined))
	 expr ...
	 )
	#,(syntax-local-introduce
            #'(require (prefix dotted-id module-name))))))))

syntax-local-introduce has the effect of taking away the mark on the
require form.

Now re-run the syntax-browser. The require form is in black (no
marks), and now it should work the way you expect.

BTW, I'm working on a better tool for understanding and debugging
such issues with macros. Email me if you have suggestions, requests,
use cases, etc.

Ryan


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 


Posted on the users mailing list.