Рассмотрим сценарий, в котором я хотел бы указать очень упрощенный язык актеров с использованием макросов Racket. Актер определяется поведением, которое определяет некоторое локальное состояние и обработчики сообщений, которые реализуют некоторую логику. Тело обработчика сообщений может использовать как формальные параметры сообщения, так и переменные состояния. Пример приведен в приведенном ниже коде.Преобразование списка символов в список идентификаторов, которые будут использоваться в макросе
В коде есть довольно много контекста, который, вероятно, даже не нужен. Тем не менее, я включил его независимо от того, чтобы предоставить пример, и тот факт, что мне нужно использовать syntax-parametrize
, может усложнить решение. Особый интерес представляет статья with-syntax
в макросе MESSAGE
, где мне нужен шаблон (local-state-variable ...)
, который соответствует списку идентификаторов, в настоящее время #'local-state-variables
, который представляет собой список символов (связанный в макросе ACTOR
) и, таким образом, не соответствует , Пока я не смог найти решение, хотя, похоже, это не должно быть ужасно сложно. Мне что-то не хватает?
#lang racket
(require (for-syntax syntax/parse))
(require racket/stxparam)
(define LOCAL_STATE
(lambda (stx)
(raise-syntax-error 'LOCAL_STATE "should only be used inside an actor" stx)))
; Define some syntax classes because abstractions are nice
(begin-for-syntax
(define-syntax-class actor-local-state
#:description "actor local state"
#:literals (LOCAL_STATE)
(pattern (LOCAL_STATE state-variable:id ...)))
(define-syntax-class message-pattern
#:description "actor message pattern"
(pattern (identifier:id argument:id ...))))
(define-syntax-parameter local-state-variables
(lambda (stx)
(raise-syntax-error 'local-state-variables "reserved keyword for actors" stx)))
(define-syntax (MESSAGE stx)
(syntax-parse stx
[(_ pattern:message-pattern body:expr ...+)
; Currently there is a "binding match failed" error on the following line, but replacing #'local-state-variables with #'(a b) (a list of identifiers) needless to say works.
(with-syntax ([(local-state-variable ...) #'local-state-variables])
; For simplicity just display the state variables - this is normally where some magic happens
#'(display '(local-state-variable ...)))]))
(define-syntax (ACTOR stx)
(syntax-parse stx
[(_ state:actor-local-state handler:expr ...+)
#'(syntax-parameterize
([local-state-variables '(state.state-variable ...)])
; For the sake of simplicity, an actor is currently a list of message handlers
(list handler ...))]))
; in this proof-of-concept code this should print (a b)
(define behaviour
(ACTOR (LOCAL_STATE a b)
(MESSAGE (add x y) (+ a b x y))))
Это было бы действительно был простым решением, но '(карта (Карри формата-идентификатор STX«~ а») местной государственной-переменные)' выдает ошибку незанятого идентификатора (для 'local-state-variables') и использует' # 'local-state-variables' интерпретирует его как синтаксический объект идентификатора 'local-state-variables'. Сложность, похоже, связана с ссылкой на параметр синтаксиса. В более широком смысле, делая переменные состояния доступными для макроса 'MESSAGE', который всегда содержится в макросе' ACTOR' (где определяются переменные состояния). – Sam