Переопределить специальный оператор с помощью MACROLET? - PullRequest
0 голосов
/ 29 февраля 2020

Я пытаюсь переопределить IF локально (цель состоит в том, чтобы встроить DSL).

Поведение действительно смущает меня. В SBCL:

(macrolet ((if (x) x)) 
  (if 'x)) ; => X

(macrolet ((if (x) x)) 
  (let ((x 2)) 
    (if 'x))) ; => Execution of a form compiled with errors.

(let ((x 2)) 
  (macrolet ((if (x) x)) 
    (if 'x))) ; => Execution of a form compiled with errors.

Есть идеи о том, почему он так себя ведет?

Я также пытался использовать интернированный символ xxx::if, но безуспешно, SBCL все еще считает, что это специальный оператор, какой бы он ни был. пакет, в котором он находится.

Есть ли способ корректно переопределить специальный оператор локально? Или, по крайней мере, буквально переопределить, что означает, что можно ввести if, и он расширяется (использование некоторого читателя magi c может помочь, но я не знаком с этим).

Обновление (решено): Точное сообщение об ошибке для второго я получил

Execution of a form compiled with errors.
Form:
  (MACROLET ((IF (X)
             X))
  (IF 'X))
Compile-time error:
  Lock on package COMMON-LISP violated when binding IF as a local macro while in
package COMMON-LISP-USER.
See also:
  The SBCL Manual, Node "Package Locks"
  The ANSI Standard, Section 11.1.2.1.2
   [Condition of type SB-INT:COMPILED-PROGRAM-ERROR]

3-й похож.

Оказывается, использование xxx::if делает это работает. Я просто не правильно скрывал символ в предыдущем эксперименте.

Простой способ заставить его работать:

(defpackage p)
(macrolet ((p::if (x) x)) 
  (let ((x 2)) 
    (p::if 'x))) ; => X

Если вы хотите наследовать другие обычные операторы CL в P, тогда просто делать (defpackage p (:use :cl) (:shadow if)).

1 Ответ

0 голосов
/ 02 марта 2020

Привязка символа if (в пакете Common Lisp, common-lisp:if) - неопределенное поведение .

Если вы хотите создать макроязык, который использует некоторые из те же имена символов, что и в стандартном Common Lisp, лучше использовать другой пакет, так что то, что выглядит как if, на самом деле mypackage:if.

Более подробно: в разделе 11.1.2.1.2 говорится, что все привязки символов пакета Common Lisp имеет неопределенное поведение за исключением случаев, когда это явно разрешено .

В подпункте 11.1.2.1.2.1 * явно разрешено связывание символа Common Lisp с macrolet 1017 *:

"Если внешний символ пакета COMMON-LISP не определен как стандартизированная функция, макрос или специальный оператор, ему разрешается лексически связывать его как макрос (например, с макросом).

Так, например, поскольку константа pi (то есть cl:pi) не является функцией, макросом или специальным оператором, (macrolet ((pi ...)) ...) может быть оценена с помощью соответствующего программа.

...