Вы работаете против разделения фаз Racket - что означает, что каждая фаза (время выполнения и время компиляции) работают в разных мирах.Как отмечает Виджай, один из способов решить эту проблему - делать то, что вы хотите во время выполнения, но это, вероятно, не будет тем, что вам нужно в долгосрочной перспективе.Дело в том, что пробуя эти вещи обычно означает, что вы захотите хранить некоторую синтаксическую информацию на уровне времени компиляции.Например, скажем, что вы хотите сохранить имена всех ваших определенных имен, которые будут использоваться во втором макросе, который распечатает их все.Вы могли бы сделать это следующим образом (здесь я использую вменяемые макросы, define-macro
- это устаревший хак, который не должен использоваться для реальной работы, вы можете посмотреть эти вещи в руководстве , а затемв ссылка ):
#lang racket
(define-for-syntax defined-names '())
(define-syntax (mydefine stx)
(syntax-case stx ()
[(_ name value)
(identifier? #'name)
(begin (set! defined-names (cons #'name defined-names))
#'(define name value))]
;; provide the same syntactic sugar that `define' does
[(_ (name . args) . body)
#'(mydefine name (lambda args . body))]))
Обратите внимание, что defined-names
определен на уровне синтаксиса, что означает, что обычный код времени выполнения не может ссылаться на него.Фактически, вы можете привязать его к другому значению на уровне времени выполнения, так как две привязки различны.Теперь, когда это сделано, вы можете написать макрос, который его использует - хотя defined-names
недоступен во время выполнения, это простая привязка на уровне синтаксиса, поэтому:
(define-syntax (show-definitions stx)
(syntax-case stx ()
[(_) (with-syntax ([(name ...) (reverse defined-names)])
#'(begin (printf "The global values are:\n")
(for ([sym (in-list '(name ...))]
[val (in-list (list name ...))])
(printf " ~s = ~s\n" sym val))))]))