Отмена определения класса и всех его методов в Common Lisp

Я хотел бы определить класс и все его методы, но после довольно тщательного поиска в Googlore я не смог найти подсказку о том, как это сделать.

Я использую реализацию Commmon Lisp под названием CCL (Clozure CL).

4 ответа

Это довольно интересный вопрос. Хотя, как указывает ответ SDS, вы можете использовать (setf (find-class 'class-name) nil) делать вещи как (make-instance 'class-name) перестать работать, это на самом деле не удаляет класс. Вы можете, например, сохранить более ранний результат (find-class …) где-нибудь еще:

CL-USER> (defclass foo () ())
#<STANDARD-CLASS FOO>
CL-USER> (defmethod show ((x foo))
           (print "x is a foo"))
STYLE-WARNING: Implicitly creating new generic function SHOW.
#<STANDARD-METHOD SHOW (FOO) {1002BFD321}>
CL-USER> (defparameter *foo-class* (find-class 'foo))
*FOO-CLASS*
CL-USER> (show (make-instance 'foo))

"x is a foo" 
"x is a foo"
CL-USER> (setf (find-class 'foo) nil)
NIL
CL-USER> (make-instance 'foo)
; Evaluation aborted on #<SIMPLE-ERROR "There is no class named ~ .. {1002FDBC61}>.
CL-USER> (make-instance *foo-class*)
#<#<STANDARD-CLASS FOO> {1003217F91}>

Я не уверен, есть ли на самом деле какой-либо способ удалить класс из системы, и не совсем ясно, что это будет означать, так как это должно было бы решить вопрос о том, что делать с любыми существующими экземплярами класса.,

(setf find-class) также не удаляет методы, специализированные для этого класса. Продолжая пример, который только начался, мы все еще можем назвать show на экземплярах класса, и мы все еще можем получить специализированные методы:

CL-USER> (show (make-instance *foo-class*))

"x is a foo" 
"x is a foo"
CL-USER> (find-method #'show '() (list *foo-class*))
#<STANDARD-METHOD SHOW ((CLASS #<STANDARD-CLASS FOO>)) {1003A7D081}>

Однако вы можете удалить применимые методы из обобщенной функции, используя REMOVE-METHOD:

CL-USER> (remove-method #'show (find-method #'show '() (list *foo-class*)))
#<STANDARD-GENERIC-FUNCTION SHOW (0)>
CL-USER> (show (make-instance *foo-class*))
; Evaluation aborted on #<SIMPLE-ERROR "~@<There is no applicable method for the generic function ~2I~_~S~ .. {1002EA5731}>.

В Common Lisp Object System (CLOS) методы не принадлежат классам, поэтому не имеет смысла говорить о "[неопределении] класса и всех его методов". Скорее CLOS имеет обобщенные функции, а программист определяет методы, которые специализируют обобщенную функцию. Как показывают приведенные выше примеры, хотя и не может быть переносимого способа отмены определения класса, вы можете удалить методы, которые являются специализированными для экземпляров этого класса, но вам придется отслеживать, что они из себя представляют. Для получения дополнительной информации, посмотрите на:

Эта тема также обсуждалась на comp.lang.lisp:

Это не переносимо, но в IDE, такой как LispWorks:

  • используйте браузер классов, перечислите все методы для класса без унаследованных, выберите методы из вызова меню методов undefine

  • в редакторе выберите defclass форма, в меню определений вызов undefine

В CCL IDE могут отсутствовать эти команды, но в SLIME + Emacs может быть что-то похожее.

Я только что наткнулся на это:

Стандартная универсальная функция #'make-instances-obsolete в HyperSpec. Обратите особое внимание на то, как он взаимодействует с#'defclass при переопределении "стандартного класса".

Также посмотрите на #'fmakunbound, #'unintern, #'delete-package а также

(remove-method
  (find-method #'<generic-function-symbol>
               '(:before :after :<some-other-qualifier-you-may-be-interested-in>)
               ;; specializers are the classes or eq specializers
               ;; in method lambda lists
               '(<first-specializer> <second-specializer-and-so-on>)))

где этот последний фрагмент кода близок к ответу Джошуа Тейлора.

Просто используйте find-class:

(setf (find-class 'myclass) nil)

Однако это не уничтожит объект класса и не удалит соответствующие методы.

Полный процесс потребует myclass символ и имена слотов класса - но вы можете использовать эти символы в другом месте, так что будьте осторожны!

Вам также придется remove-method из общих функций, для которых вы их определили.

Короче говоря, это огромное предприятие, безусловно, не стоящее усилий.

Просто перезапустите сеанс Lisp.

Пару недель назад я обнаружил, что удаляю пакет, над которым работал, и перезагружаю файл lisp, чтобы получить тот же желаемый эффект (он работает, хотя я согласен, что это немного излишне, поскольку вы теряете все, что определено в этом пакете).

Предполагая, что определение вашего класса находится в отдельном пакете (и, возможно, в отдельном файле для этого пакета), просто переключитесь на пакет cl, затем удалите свой пакет, перезагрузите, снова переключитесь на свой пакет. Пример (из моей подсказки sbcl):

TESTPACKAGE> (in-package :cl)
CL> (delete-package :testpackage)
CL> (load "testpackage.lisp")
CL> (in-package :testpackage)
TESTPACKAGE> 
Другие вопросы по тегам