Macro in Racket language?

> (version)
"8.8"
> (require (for-syntax racket/base))
> (define-syntax-rule (make-module n (l ...) i b)
    (module n racket/base
      (require l ...)
      (provide i)
      (define i b)))
> (make-module t () x 1)
string:1:20: ?: literal data is not allowed;
 no #%datum syntax transformer is bound
  at: 1
 [,bt for context]
> (make-module t (racket/base) x 1)

Anyway, the macro can be expanded successfully at last, but I don't want to import the library twice. What should I do? Or is this documented?

1 Like

I think the problem is how #%datum is introduced.

When #%datum is introduced it gets the lexical information from the
syntax object (that needs to wrapped in #%datum).
In the form (make-module t () x 1) the 1 will become (#%datum . 1)
but the #%datum has lexical information from outside the t module.
So you get the "no #%datum syntax transformer is bound" error.

How to solve the problem depends on where you want b to get its context.

One option:

(define-syntax (make-module stx)
  (syntax-case stx ()
    [(_make-module n (l ...) i b)
     (with-syntax ([b (datum->syntax #'stx (syntax->datum #'b))])
       (syntax/loc stx
         (module n racket/base
           (require l ...)
           (provide i)
           (define i b))))]))
1 Like

Thanks for your kind explanation, sir!

But there still remains a question. Why does the error just disappear when we explicitly import the library in the t module?

It boils down to how (require module-path) works.

(require module-path)

Imports all exported bindings from the named module,
using the export name for the local identifiers.
The lexical context of the module-path form determines the
context of the introduced identifiers, a ...

So in (make-module t (racket/base) x 1) the racket/base and 1
have the same lexical context. When inserted in (require l ...)
the imported binding for #%datum will have the same context as 1.
And when the implicit #%datum is added, it will now be bound.

Thank you very much, sir!

But according to the documentation,

The module-path form must be as for require, and it supplies the initial bindings for the body forms. That is, it is treated like a (require module-path) prefix before the forms, except that the bindings introduced by module-path can be shadowed by definitions and requires in the module body forms.

Is this case an exception?

In

(module n racket/base ...)

the context of the racket/base is "inside the module n".

Likewise, in:

(module n racket/base 
   (require racket/base)
    ...)

the context of racket/base is also inside module n, so this is fully redundant.

However, in your example (make-module t (racket/base) x 1) the context of
racket/base is "from outside the module n", so the bindings of (require racket/base)
will get that context.

Oh, I see. Sorry for bothering you!