Рассмотрите очень простой язык актера, на котором актер определяет какое-либо локальное состояние и некоторые методы, которые могут быть вызваны путем отправки сообщений актеру. В своей реализации один такой метод актера может быть преобразован в функцию, которая определяет формальные параметры метода и принимает текущее локальное состояние актера. Вызов метода возвращает новое локальное состояние.Динамически связывающие свободные идентификаторы в функциональном теле
Привязка формальных параметров в теле не проблема, но привязка локального состояния кажется сложнее. В примере в конце кода ниже, в теле save
, a
останется несвязанным, несмотря на то, что a
(другое a
) связано сгенерированной функцией evaluate-body
в макросе METHOD
. Критическая точка в образце коды ниже, таким образом, METHOD
макро, более конкретно evaluate-body
функции (что, где связывание должно произойти, это означает, что мой дизайн программы является разумным)
Есть ли способ гигиенический связать этот произвольный набор бесплатные идентификаторы (в настоящее время только содержащие a
, но это может быть что-нибудь, действительно)?
#lang racket
(require (for-syntax syntax/parse))
(require racket/stxparam)
(struct actor (local-state methods))
(struct method (name formal-parameters body))
(define-syntax-parameter local-state-variables #f)
(define-syntax (ACTOR stx)
(syntax-parse stx
[(_ (LOCAL_STATE state-variable ...) method:expr ...+)
#'(syntax-parameterize ([local-state-variables '(state-variable ...)])
; For the sake of simplicity, an actor is currently a list of message handlers
(actor
(make-list (length '(state-variable ...)) (void))
(list method ...)))]))
(define-syntax (METHOD stx)
(syntax-parse stx
[(_ (name:id formal-parameter:id ...) body:expr ...+)
(with-syntax ([(local-state-variable ...) (syntax-parameter-value #'local-state-variables)])
#'(method
'name
'(formal-parameter ...)
(λ (formal-parameter ... #:local-state [current-state '()])
; the "a" that will be bound here is different from the free identifier "a" in the body
(define (evaluate-body local-state-variable ...)
body ...
(list local-state-variable ...))
(apply evaluate-body current-state))))]))
(ACTOR (LOCAL_STATE a)
(METHOD (save new-a)
; "a" is an unbound identifier
(set! a new-a)))
Это потрясающе. К настоящему времени я хорошо знаком с крупными частями макросистемы (как ее использовать), но получаю глубокое понимание того, как все это _works_ все еще довольно сложно. Спасибо за этот проницательный ответ! – Sam