2016-08-30 4 views
2

syntax-parameterize обычно используется в сочетании с make-rename-transformer так, что синтаксис-параметр p ведет себя как псевдоним для другого идентификатора:параметр синтаксиса, указывающий на переменную синтаксиса-шаблона?

#lang racket 

(require racket/stxparam) 
(define-syntax-parameter p #f) 

(define-syntax (test-1-p stx) 
    (syntax-case stx() 
    [(_ body) 
    #'(let ([tmp 123]) 
     (syntax-parameterize ([p (make-rename-transformer #'tmp)]) 
      body))])) 
(test-1-p p) ;; prints 123 

Код выше работает хорошо, как и tmp является идентификатором связанным let. Если же я пытаюсь сделать p псевдоним для переменного шаблона tmp связанных with-syntax, то он не работает, как ожидалось:

#lang racket 

(require racket/stxparam) 
(define-syntax-parameter p #f) 

(define-syntax (test-2-p stx) 
    (syntax-case stx() 
    [(_ body) 
    #'(with-syntax ([tmp #'(foo 123)]) 
     (syntax-parameterize ([p (make-rename-transformer #'tmp)]) 
      body))])) 
(test-2-p #'p) ;; gives #'p, instead of #'(foo 123) 

Если вместо этого я объявляю синтаксис p-unhygienic, и привязать его к (make-rename-transformer #'tmp), то это работает штраф:

#lang racket 

(define-syntax (test-3-p stx) 
    (syntax-case stx() 
    [(_ body) 
    #`(with-syntax ([tmp #'(foo 123)]) 
     (define-syntax #,(syntax-local-introduce #'p-unhygienic) 
      (make-rename-transformer #'tmp)) 
     body)])) 
(test-3-p #'p-unhygienic) ;; gives #'(foo 123), as expected 

Как я могу создать гигиенический псевдоним для переменного шаблона с помощью syntax-parameterize?

ответ

2

Это интересный случай, я ожидал того же, что и вы. Это может быть либо ошибка, либо ограничение; Я не уверен. В любом случае форма define-rename-transformer-parameter предоставляется в качестве обходного пути.

Исходное значение параметра переименования-трансформатора должно быть переименованным трансформатором, поэтому вы можете использовать идентификатор p-init с #f в качестве привязки трансформатора.

(define-syntax p-init #f) 
(define-rename-transformer-parameter p (make-rename-transformer #'p-init)) 

В контексте:

#lang racket 

(require racket/stxparam) 
(define-syntax p-init #f) 
(define-rename-transformer-parameter p (make-rename-transformer #'p-init)) 

(define-syntax (test-2-p stx) 
    (syntax-case stx() 
    [(_ body) 
    #'(with-syntax ([tmp #'(foo 123)]) 
     (syntax-parameterize ([p (make-rename-transformer #'tmp)]) 
      body))])) 
(test-2-p #'p) ; #<syntax:10:28 (foo 123)> 
+1

Это не ошибка, хотя это * * является ограничением. В документации для 'syntax-parameterize' указано, что« Если 'expr' создает результат« make-rename-transformer », тогда' id' может использоваться как макрос, который расширяется до использования целевого идентификатора, но 'syntax- local-value' 'id' не дает значения цели.« Я не совсем уверен, почему это ограничение существует, но было бы интересно найти объяснение. В статье о синтаксических параметрах, похоже, не упоминается. Я предполагаю, что сами параметры синтаксиса используют косвенное отношение, которое делает их несовместимыми с «синтаксисом-локальным значением» напрямую. –

+0

В этом случае было бы задачей 'синтаксиса 'просматривать синтаксические параметры так же, как и через переименовать-трансформаторы? –

+0

Я так не думаю. Лично, если это что-то трудное, чтобы справиться с этим правильно, я бы подумал, что это будет «синтаксис-локальный-значение», так как в противном случае каждый макрос, который использует «синтаксис-локальное значение», должен также добавить специальную обработку для параметров синтаксиса. Конечно, из-за того, как параметры синтаксиса реализованы в Racket, тогда как «синтаксис-локальный-значение» реализован на C, это может быть сложным, но похоже, что здесь нужно улучшить сотрудничество. –

Смежные вопросы