LISP: Как создать специализацию временного метода в рамках
-
24-10-2019 - |
Вопрос
В Common LISP: переопределить существующую функцию в области прицела? ОП попросил что -то подобное. Но я хочу создать специалист по методу, а не функцию. По сути предположим, что метод определяется таким:
defmethod my-meth ((objA classA) (objB classB)) (...)
Я хотел бы сделать (псевдокод):
(labels ((my-meth ((objA classA) (objB (eql some-object)))))
do stuff calling my-meth with the object...)
Реальное использование в том, что я хочу создать временную среду, где setf slot-value-using-class
будет специализироваться на eql
, Essentialy, создавая конкретный объект по требованию по требованию его написания слотов. (Цель состоит в том, чтобы записать где -то старые и новые значения слотов, а затем вызовать следующий метод.) Я не хочу создавать Metaclass, потому что я могу захотеть перехватить уже созданные стандартные объекты.
Конечно, я попробовал это, и это не сработало (потому что как ты DEFMETHOD
в LABELS
?) Но я хотел, чтобы несколько более опытных людей проверили, что это не выполнимо таким образом и/или предложить подходящий путь.
Комментарии?
РЕДАКТИРОВАТЬ:
Даниэль и Терье предоставляют отличные ссылки для расширения моих знаний о возможностях, но я хочу подтолкнуть его немного больше для поиска более ванильного подхода, прежде чем идти туда. Я стремился делать добавление-метод при входе в окружающую среду, который будет специализироваться на EQL и выполнять Method после выхода. Я еще не закончил. Если бы кто -то играл с ними, комментарии были бы неплохо. Будет держать нить в курсе.
РЕДАКТИРОВАТЬ 2: Я близок, чтобы сделать это со сценарием Add-Method, но есть проблема. Вот что я попробовал:
(defun inject-slot-write-interceptor (object fun)
(let* ((gf (fdefinition '(setf sb-mop:slot-value-using-class)))
(mc (sb-mop:generic-function-method-class gf))
(mc-instance (make-instance (class-name mc)
:qualifiers '(:after)
:specializers (list (find-class 't)
(find-class 'SB-PCL::STD-CLASS)
(sb-mop::intern-eql-specializer object)
(find-class 'SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION))
:lambda-list '(new-value class object slot)
:function (compile nil (lambda (new-value class object slot) (funcall fun new-value class object slot))))))
(add-method gf mc-instance)
(defun remove-slot-write-interceptor ()
(remove-method gf mc-instance))
))
(defun my-test (object slot-name data)
(let ((test-data "No results yet")
(gf (fdefinition '(setf sb-mop::slot-value-using-class))))
(labels ((show-applicable-methods () (format t "~%Applicable methods: ~a" (length (sb-mop:compute-applicable-methods gf (list data (class-of object) object (slot-def-from-name (class-of object) slot-name)))))))
(format t "~%Starting test: ~a" test-data)
(show-applicable-methods)
(format t "~%Injecting interceptor.")
(inject-slot-write-interceptor object (compile nil (lambda (a b c d) (setf test-data "SUCCESS !!!!!!!"))))
(show-applicable-methods)
(format t "~%About to write slot.")
(setf (slot-value object slot-name) data)
(format t "~%Wrote slot: ~a" test-data)
(remove-slot-write-interceptor)
(format t "~%Removed interceptor.")
(show-applicable-methods)
)))
Вызов (мой тест) с некоторым слотом для объекта и данными, поскольку ARGS приводит к:
Starting test: No results yet
Applicable methods: 1
Injecting interceptor.
Applicable methods: 2
About to write slot.
Wrote slot: No results yet <----- Expecting SUCCESS here....
Removed interceptor.
Applicable methods: 1
Так что я застрял здесь. Специализация работ, поскольку применимые методы теперь включают EQL-специфированный: после метода, но, к сожалению, он, похоже, не вызван. Может ли кто -нибудь помочь, чтобы я мог закончить с ним и реорганировать его на сладкий маленький утилитный макрос?
Решение
Нет, вы не можете определить динамическую протяженность или лексическую оцеленную специализированную метод в Common LISP.
Аспект, ориентированное на программирование может использоваться в качестве подхода для решения основной проблемы. Смотрите также Контекстное программирование.
Контекст является библиотекой, которая обеспечивает аспекты / контекст -ориентированные расширения для обычного LISP / Clos.
Легкая альтернатива-использовать специальную/динамическую переменную, чтобы указать, когда метод должен выполнять журнал:
(defparameter *logging* NIL "Bind to a true value to activate logging")
(defmethod my-meth :around ((objA classA) (objB (eql some-object)))
(prog2
(when *logging*
(logging "Enter my-meth"))
(call-next-method)
(when *logging*
(logging "Exit my-meth"))))
(let ((*logging* T))
(do stuff calling my-meth with the object...))
Примечание, однако, что метод вокруг будет называться также при отключении регистрации.
Другие советы
Похоже, что когда -то был generic-flet
а также generic-labels
Специальные формы, предложенные для обычного LISP, но он был удален из окончательных характеристик, потому что он был признан редко поддерживаемым реализациями и плохо спроектированными. Видеть Выполните общий флета-пенько, разработанная рецензией в гиперсспешении. Интересно прочитать дискуссии, почему люди думали, что лексические методы были менее полезны, чем лексически ометные функции.
Итак, без них я не думаю, что есть способ создать лексически метод, хотя я не играл с Contextl, с которым Terje связывал в другом ответе, так что возможно, что предоставит вам то, что вам нужно.