3

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.

RogerTheDragon
  • 267
  • 1
  • 10
  • 2
    Although I don't know if you'll find it helpful, I wrote [Fear of Macros](http://www.greghendershott.com/fear-of-macros/). – Greg Hendershott Sep 17 '13 at 15:41
  • Okay, my intuition of the problem is that the syntax/identifier `nm` is being created with lexical info which places it outside of the new module `mod`, sort of. Maybe I'm wrong. Either way I have no idea how to fix this. – RogerTheDragon Sep 17 '13 at 15:42
  • @GregHendershott, right, I'd stumbled upon that – will pay it some more attention. Thanks for the pointer, perhaps I should work through it thoroughly. – RogerTheDragon Sep 17 '13 at 15:43
  • Your question has me stumped. Because it's related to a question I saw on users@racket-lang.org last week, I [posted a message there](http://lists.racket-lang.org/users/archive/2013-September/059537.html) just now. – Greg Hendershott Sep 17 '13 at 17:43
  • 1
    I mentioned this in your other post, but Matthew Flatt's recent Clojure/West talk explains a lot about Racket's macros (though perhaps not this exact issue): http://www.infoq.com/presentations/racket – stchang Sep 17 '13 at 20:57
  • Indeed I've already watched that presentation twice, but I don't think I understand 100% of the details. It gets better every time, though :) Thanks for the pointers, @stchang and @Greg! – RogerTheDragon Sep 18 '13 at 09:30

1 Answers1

3

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)))]))
stchang
  • 2,555
  • 15
  • 17
  • Right, I'd indeed already discovered by trial-and-error that the position of the `require` was crucial, so I guess the next logical step is what you propose. Seeing the answers to this and my previous question, I guess that the way to "splice" code is indeed like you're showing, using `with-syntax`. Anyway, thank you very much, once again! I feel as if I haven't RTFM, so I'll try harder to understand what's written down. – RogerTheDragon Sep 18 '13 at 09:29
  • I think learning by-need like you are doing is the way to go and it seems like you already understand most of the fundamentals. Aimlessly reading the docs without a specific goal usually results in not retaining anything, at least for me. – stchang Sep 18 '13 at 17:16