2014-09-23 2 views
5

Хороший вопрос был задан на канале #scheme Freenode. Рассмотрим следующий код на схеме:Макросы и внутренние определения на схеме

(define alpha 1) 

(define-syntax foo 
    (syntax-rules (quote alpha) 
    ((_ alpha msg) (define bar 2)) 
    ((_ other msg) (syntax-error msg)))) 

(define (beta) 
    (foo alpha "beta") 
    (define alpha 3) 
    'beta) 

(define (gamma) 
    (define alpha 4) 
    (foo alpha "gamma") 
    'gamma) 

(define (delta alpha) 
    (foo alpha "delta") 
    'delta) 

какие из beta, gamma и delta должны производить синтаксические ошибки? И какие сделать? Я проверил это с Chibi Scheme, где beta в порядке, а gamma и delta сбой. Интересно, является ли это предполагаемым поведением или просто ошибкой в ​​Chibi.

Согласно стандарту, кажется, что расширение макросов должно происходить до того, как внутренние определения будут переписаны в letrec*. Таким образом, beta и gamma должны оба сбой, так как foo будет соответствовать внутренне определенному alpha, а не глобальному.

Однако явно не указано в стандарте как внутренние определения фактически работают, только то, что они могут рассматривать как letrec ярлык. Я получаю такое же поведение с R5RS Racket, так что кажется, что я пропускаю что-то в стандарте, который требует такого поведения.

+0

В R6RS (psyntax based impl), я получаю такое же поведение при вызове процедур. – leppie

ответ

1

Okay, I , наконец понять ваш вопрос. Запуск вашего кода был сложным, потому что у вас появилась функция «синтаксическая ошибка», которая сигнализирует синтаксическую ошибку, только если она завершается в полностью расширенном коде. Без разницы.

Я думаю, что ответ на ваш вопрос заключается в следующем:

Этих ребят Scheme (Дибвиг, Felleisen, Hieb, Clinger, Rees, Wand, Флэтта, Калпеппер и т.д.) довольно умный!

В частности, как-то Scheme/Racket удается выяснить, как работает структура связывания, даже если она не знает, что будет связывать или нет. Ты прав! Это безумие! Но алгоритм, описанный Dybvig et al. делает некоторые очень умные вещи, чтобы гарантировать, что гигиена отслеживает, являются ли идентификаторы равными «идентификатор-равный» или «связанный-идентификатор-равный» (терминология Флатта), даже если он еще не знает, какой из них связывает другой. Я лично рекомендую прочитать «Макросы, которые работают вместе» (Flatt, Culpepper, Darais, Findler) для лучшего понимания этого.

Извините, если я неправильно понял ваш вопрос или мой тон неуместен!

1

Возможно, это будет слишком много в зависимости от стороны реализации, но это происходит из-за порядка расширения макросов. Теоретически, все определения содержат alpha, поэтому он не должен совпадать с одним в литеральных ключевых словах. Тем не менее, макрорасширение должно быть выполнено до того, как формы define будут расширены до letrec*, иначе компилятор не сможет правильно определить внутреннее определение. Поэтому в тот момент компилятор может видеть или не видеть привязки. (Макрос время расширения не указано на R7RS, поэтому реализация может выбирать собственные сроки, а также.)

Для beta случае компилятор не расслышал связывание так макросъемки расширителя до сих пор можно увидеть, что alpha одно и то же как глобальный. Другие случаи - это наоборот.

0

Прежде всего, delta выходит (не должно совпадать alpha), потому что он явно лексический связывает alpha к другому связыванию, чем тот, в соответствии с которой ваш sytnax-rules появляется. Интересными являются beta и gamma.

Согласно разделу 5.2.2. R4RS (стр. 13) и R5RS (стр. 16), раздел 5.3.2. R7RS (стр. 26) и раздел 11.3. R6RS (стр. 32), «область» привязки, установленная внутренним определением, представляет собой весь <body>, в котором отображается определение. И ваш макро-вызов foo явно находится в пределах того же <body>, что и эти внутренние определения.

R7RS также идет немного дальше и предупреждает нас:

Обратите внимание, что такое тело [т.е. тот, который содержит внутренние определения], может быть не очевидным до тех пор, пока не произойдет расширение другого синтаксиса.

Таким образом, испорченный порядок событий допускается, но нет никакой двусмысленности; ваш syntax-rules не должен совпадать с веткой alpha, если есть привязка для alpha по любому внутреннему определению в том же <body>, что и вызов макроса. Таким образом, beta и gamma также отсутствуют.

Приложение A

Если мы усложнили ситуацию дальше, и ваш макрос сам условно связан alpha, как

(syntax-rules (alpha) 
    ((_ alpha x) (define alpha x))) 

то кажется, действительно неоднозначная на первый взгляд, но я считаю, что это что макрорасширитель переименует определенный идентификатор alpha в соответствии с гигиеной, то есть мы не будем затенять alpha, который мы сопоставляем как литерал, так что это хорошо, и e выше просто создаст привязку для переименованного alpha, недоступного вне тела макроса.

Приложение B

Существует ограничение в конце раздела 5.3. R5RS (стр. 17), конец раздела 5.4. из R7RS (стр. 26) и в середине раздела 10. в R6RS (стр. 30), в которых упоминается, что последовательность определений не должна содержать определения, которое изменяет значение любого из них. (На самом деле это немного сложнее, все три стандарта используют разные формулировки, но это должно быть разумным сводкой.)

В вашем примере мне не ясно, будет ли вероятность того, что ваша syntax-rules будет расширяться до синтаксической ошибки как двусмысленность его «смысла». Если вы считаете это неоднозначным, то ваши beta и gamma являются «ошибками» (неопределенное поведение) в соответствии с R5RS и R7RS и «синтаксическим нарушением» в соответствии с R6RS.

Если ваш пример содержит другое обязательство во второй ветви вашего syntax-rules (в идеале это определение для одной и той же переменной равно), то этот нитпик не будет применяться, поэтому ваш вопрос стоит.

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