Я пытаюсь переопределить IF локально (цель - встроить DSL).
Поведение меня действительно смущает. В СБКЛ:
(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
, и оно будет расширено (может помочь использование некоторой магии чтения, но я не знаком с этим).
Обновление (решено): точное сообщение об ошибке для второго, которое я получал
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))
.
p::if
, я не получаю ошибок от 2-й и 3-й версии, только предупреждения о неиспользуемой переменной X. Это понятно, потому что вы цитируетеx
в теле, а не используете переменную. - person Barmar   schedule 29.02.20202
без предупреждений, если я удалю кавычку передx
. - person Barmar   schedule 29.02.2020sb-ext:unlock-package :cl
. Возможно, какое-то вмешательство в блокировку пакетов? Позвольте мне попробовать со свежим REPL. - person BlueFlo0d   schedule 29.02.2020(let ((x 2)) (macrolet ((cl-user::if (x) x)) (cl-user::if 'x)))
в новом обновлении. Я на SBCL 1.5.1. Зависит ли эта реализация? - person BlueFlo0d   schedule 29.02.2020cl-user::if
, создайте свой собственный пакет и используйтеmypackage::if
- person Barmar   schedule 29.02.2020(defpackage p (:use :cl) (:shadow if)) (macrolet ((p::if (x) x)) (p::if 'x))
теперь у меня работает. Большое спасибо! - person BlueFlo0d   schedule 29.02.2020(make-package 'p)
, а затем использовалp::if
. Нет необходимости наследовать или скрывать что-либо. - person Barmar   schedule 29.02.2020(defpackage p)
и(make-package 'p)
недостаточно указаны для переносимого Common Lisp. Неизвестно, какие пакеты они используют. SBCL, как известно, не использует ни одного из них. - person Rainer Joswig   schedule 29.02.2020