Генерация 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)))]))