Переопределение "defun" в пакете
Я хотел бы определить макрос с именем "defun" из пакета, который я создаю, и я хотел бы экспортировать его для использования в определенных местах. Есть библиотека под названием parenscript, которая делает это в своем пакете следующим образом:
(export #:defun)
Когда я пытаюсь сделать это в моем собственном пакете, я получаю эту ошибку SBCL
Lock on package COMMON-LISP violated when defining DEFUN as a macro while in package COMMON-LISP-USER.
Как это делается в библиотеке parenscript? Я знаю, что вы можете напечатать форму;
(ps (defun function-name (args) (body)))
Я хочу быть в состоянии сделать то же самое, но не могу понять, как это сделать?
2 ответа
Вы хотите затенить оригинальный символ из пакета CL.
CL-USER 1 > (defpackage "MY-PACKAGE" (:use "CL"))
#<The MY-PACKAGE package, 0/16 internal, 0/16 external>
CL-USER 2 > (in-package "MY-PACKAGE")
#<The MY-PACKAGE package, 0/16 internal, 0/16 external>
MY-PACKAGE 3 > (shadow 'defun)
T
MY-PACKAGE 4 > (cl:defun defun () :my-defun-returns)
DEFUN
MY-PACKAGE 5 > (defun)
:MY-DEFUN-RETURNS
MY-PACKAGE 6 > (export 'defun)
T
Вам нужно прочитать больше о пакетах и символах. Здесь я собираюсь квалифицировать все символы, когда это необходимо, чтобы не было двусмысленности относительно того, о чем я говорю.
Вы не можете переопределить
CL:DEFUN
это вызывает неопределенное поведение, и вы, скорее всего, "сломаете" свою среду выполнения, сделав ее непригодной для использования. Вот почему в SBCL существует концепция блокировок для пакетов, которая позволяет избежать ошибочного изменения пакета и его привязок (вы все равно можете разблокировать пакет, который обычно не требуется).В рамках вашего макроса, вы можете интерпретировать
CL:DEFUN
как вы хотите, именно это и делает Parenscript, переводя подмножество фактического кода на Лиспе в Javascript.В любой другой упаковке
P
Вы можете определитьP:DEFUN
как переменная / функция / макрос / все, что полностью отличается отCL:DEFUN
, Вы можете экспортировать его, и все в порядке, вы можете использовать обаP:DEFUN
а такжеCL:DEFUN
как вы хотите.Конфликты могут возникнуть, если вы хотите написать неквалифицированную
DEFUN
Символ и пусть читатель узнает, на какие символы ссылаются. Как правило, пользователи библиотеки могут определять пакет следующим образом:(defpackage :foo (:use :cl :p))
Это приводит к конфликту, потому что и пакеты "CL", и пакеты "P" экспортируют "DEFUN". Один из способов решить эту проблему - определить диалект Common Lisp, который перепривязывает
DEFUN
и повторно экспортирует все другие символы из "CL". Затем ваши пользователи должны использовать только ваш пакет, а не пакет CL. Другой способ - использовать CL и shadow-import только "DEFUN" из P, так чтоDEFUN
это псевдоним дляP:DEFUN
(следовательно, вам нужно написатьCL:DEFUN
явно ссылаться на макрос Common Lisp).
Ссылка, приведенная выше, входит в более подробную информацию.