Переопределение «defun» в пакете - PullRequest
3 голосов
/ 02 июня 2019

Я хотел бы определить макрос с именем "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 ]

3 голосов
/ 02 июня 2019

Вы хотите скрыть оригинальный символ из пакета 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
2 голосов
/ 02 июня 2019

Вам нужно больше узнать о пакетах и ​​символах .Здесь я собираюсь квалифицировать все символы, когда это необходимо, чтобы не было никакой двусмысленности, о которой я говорю.

  1. Вы не можете переопределить CL:DEFUN, это вызывает неопределенное поведение, и выскорее всего "сломает" вашу среду выполнения, сделав ее непригодной для использования.Вот почему в SBCL есть концепция блокировки для пакетов, которая позволяет избежать ошибочного изменения пакета и его привязок (вы все равно можете разблокировать пакет, который обычно не требуется).

  2. В рамках вашего макроса вы можете интерпретировать CL:DEFUN по своему желанию, что и делает Parenscript, переводя подмножество фактического кода Lisp в Javascript.

  3. В любом другом пакете P вы можете определить P:DEFUN как переменную / функцию / макрос / независимо от того, что полностью отличается от CL:DEFUN.Вы можете экспортировать его, и все в порядке, вы можете использовать как P:DEFUN, так и CL:DEFUN, как хотите.

  4. Конфликты могут возникать, если вы хотите написать неквалифицированный символ 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).

Приведенная выше ссылка более детально описана.

...