Правила синтаксиса схемы — разница в связывании переменных между (let) и (define)

В спецификации R5RS указано, что в рамках требований к макросу, определенному с помощью syntax-rules:

Если преобразователь макроса вставляет свободную ссылку на идентификатор, ссылка ссылается на привязку, которая была видна там, где был указан преобразователь, независимо от любых локальных привязок, которые могут окружать использование макроса.

Я пытаюсь понять, как это работает на практике. Так, например, если у меня есть следующий код:

(define var 'original)

(define-syntax test-var
 (syntax-rules (var)
   ((_ var)
    var)
   ((_ pattern-var)
    'no-match)))

Я ожидаю, что следующее, если оно будет выполнено сразу после этого, будет оцениваться как original, что оно и делает:

(test-var var)

И я ожидаю, что это будет no-match, поскольку var, введенное в область видимости до test-var, не соответствует привязке var в определении макроса:

(let ((var 1)) (test-var var))

Однако следующий пример меня озадачил:

(define var 'new-var)
(test-var var)

В Chicken Scheme это оценивается как new-var. Я ожидал, что это будет no-match по тем же причинам, что и в предыдущем примере (let). Я подумал, что, возможно, это проблема с двойным использованием define, но результат все равно new-var, даже если я использую (set! var 'new-var)

Есть ли у кого-нибудь понимание того, что здесь происходит? Что должно произойти за R5RS?


person Justin Ethier    schedule 03.11.2011    source источник


Ответы (1)


Это обычная уловка, которую используют Schemes при работе с переопределениями в REPL — рассматривая их как мутацию для существующей привязки. Таким образом, второй define на самом деле не создает новую привязку, а просто set! создает существующую.

person Eli Barzilay    schedule 03.11.2011
comment
Интересно... хотя такое поведение происходит не только в REPL, но и при запуске через интерпретатор или даже скомпилированную версию кода. - person Justin Ethier; 03.11.2011
comment
Так правильно ли говорить, что это не специфицированное поведение, но большинство интриганов ожидает, что оно будет работать таким образом? - person Justin Ethier; 03.11.2011
comment
Что ж, под REPL я подразумеваю любое использование неявного глобального пространства имен, в отличие от использования модульной системы, где такие переопределения обычно запрещены. - person Eli Barzilay; 03.11.2011
comment
Если вы хотите быть придирчивым, то R⁵RS говорит: «На верхнем уровне программы определение (define <variable> <expression>) имеет по сути тот же эффект, что и выражение присваивания (set! <variable> <expression>), если <variable> связано». Так что я предполагаю, что интриганы ожидали этого. Но работа без модульной системы довольно устарела, и код, который зависит от верхнего уровня, должен быть ограничен быстрыми играми и отладкой... По крайней мере, IMO. - person Eli Barzilay; 03.11.2011