Pregunta

Okay, I must be really daft. I'm trying to create a macro (part of a larger undertaking) that given a function, wraps it in its own submodule, then requires it, so that functions defined thusly cannot mess around with surrounding terms, but that the rest of their host module can use them as normal. Perhaps this isn't a good idea, but humour me – I cannot see why it should be impossible.

I've got the following minimal code example, in two files.

tinylang.rkt:

(provide (all-defined-out))

(define-syntax (modularise stx)
  (syntax-case stx ()
[(_ func)
 (with-syntax ([mod (datum->syntax stx 'testmodule)]
               [nm  (datum->syntax stx 'working)]
               )
   #`(begin

       (print (list "Defining module " 'mod))(newline)

       (module mod racket
         (provide nm)
         (define  nm func)
       )

       (require (for-syntax (submod "." mod))) ;; at least kills a syntax error
       (require (for-template (submod "." mod))) ;; doesn't help
    ))]))

tinyimp.rkt:

#lang racket
(require "tinylang.rkt")
(modularise (lambda () (display "this works!")))
; the following line would make everything work!
;(require (submod "." testmodule))
(working)

I feel guilty about spamming this site with questions which I feel should be trivial for me to solve with the documentation, but it's still not clear for me what happens at what stage. If someone knows a good resource (book, lecture, paper) I'd be really happy to hear about it. I know about the Racket documentation, which is really extensive, but often I miss the crucial details in the explanations there.

¿Fue útil?

Solución

Yes, macro-generated requires and provides are tricky. They key is the lexical scope of the require-spec (ie the (submod "." testmodule)).

From the docs:

In require ... the generator of the require-spec determines the scope of the bindings.

In other words, the require-spec and the uses of required identifiers must have the same scope.

Here is a version of tinylang.rkt that will work:

#lang racket

(provide (all-defined-out))

(define-syntax (modularise stx)
  (syntax-case stx ()
    [(_ func)
     (with-syntax ([require-spec (datum->syntax stx '(submod "." testmodule))])
       #`(begin
           (module testmodule racket
             (provide working)
             (define working func))
           (require require-spec)))]))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top