Я пытаюсь переопределить 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))
.