Может (или должно) расширение макроса иметь побочные эффекты? Например, вот макрос, который на самом деле идет и захватывает содержимое веб-страницы во время компиляции:
#lang racket
(require (for-syntax net/url))
(require (for-syntax racket/port))
(define-syntax foo
(lambda (syntx)
(datum->syntax #'lex
(port->string
(get-pure-port
(string->url
(car (cdr (syntax->datum syntx)))))))))
Затем я могу сделать (foo "http://www.pointlesssites.com/")
и он будет заменен на "\r\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\r\n\t <and so on>"
Это хорошая практика или нет? Гарантирую ли я, что Racket запустит этот код только один раз? Если я добавлю в макрос строку (display "running...")
, он напечатает только один раз, но мне бы не хотелось обобщать один пример...
PS - причина, по которой я спрашиваю, в том, что я действительно думаю, что иногда это может быть действительно полезно. Например, это — это библиотека, которая позволяет вам загружать (во время компиляции) документ обнаружения из Google API Discovery и автоматически создавать для него обертки. Я думаю, было бы очень здорово, если бы библиотека действительно получала документ обнаружения из Интернета, а не из локального файла.
Кроме того, чтобы привести пример макроса с различными побочными эффектами: однажды я создал макрос, который переводил небольшое подмножество Racket в (эта-расширенное) лямбда-исчисление (которое, конечно, все еще работает в Racket). Всякий раз, когда макрос заканчивал перевод функции, он сохранял результат в словаре, чтобы последующие вызовы макроса могли использовать определение этой функции в своих собственных переводах.