Может (или должно) расширение макроса иметь побочные эффекты? Например, вот макрос, который фактически идет и захватывает содержимое веб-страницы во время компиляции:
#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 - причина, по которой я спрашиваю, потому что я на самом деле думаю, что иногда это может быть действительно полезно. Например this - это библиотека, которая позволяет загружать (во время компиляции) документ обнаружения из службы Google API Discovery и автоматически создавать обертки для Это. Я думаю, было бы действительно здорово, если бы библиотека на самом деле взяла документ обнаружения из Интернета, а не из локального файла.
Кроме того, чтобы привести пример макроса с различными видами побочных эффектов: однажды я создал макрос, который перевел небольшое подмножество Racket в (eta-расширенное) лямбда-исчисление (которое, конечно же, все еще выполняется в Ракетка). Всякий раз, когда макрос завершает перевод функции, он сохраняет результат в словаре, чтобы последующие вызовы макроса могли использовать определение этой функции в своих собственных переводах.