Генерация require-предложений с помощью макросов Racket

Хорошо, я должен быть действительно глупым. Я пытаюсь создать макрос (часть более крупного предприятия), который дает функцию, оборачивает ее в свой собственный подмодуль, затем requireЭто так, что функции, определенные таким образом, не могут связываться с окружающими терминами, но что остальные их модули могут использовать их как обычно. Возможно, это не очень хорошая идея, но порадуйте меня - я не понимаю, почему это должно быть невозможно.

У меня есть следующий минимальный пример кода, в двух файлах.

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)

Я чувствую себя виноватым из-за спама на этом сайте с вопросами, которые, по моему мнению, должны быть тривиальными для меня, чтобы решить с документацией, но мне все еще не ясно, что происходит на каком этапе. Если кто-то знает хороший ресурс (книга, лекция, статья), я был бы очень рад услышать об этом. Я знаю о документации Racket, которая действительно обширна, но часто я упускаю важные детали в объяснениях там.

1 ответ

Решение

Да, сгенерированный макрос требует и предоставляет сложно. Их ключ - это лексическая область применения require-spec (т.е. (submod "." testmodule)).

Из документов:

В require... генератор require-spec определяет область привязок.

Другими словами, require-spec и использование обязательных идентификаторов должны иметь одинаковую область видимости.

Вот версия tinylang.rkt, которая будет работать:

#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)))]))
Другие вопросы по тегам