LISP:如何在范围内创建临时方法专业
-
24-10-2019 - |
题
在 常见的LISP:重新定义范围内的现有功能? OP要求提供类似的东西。但是我想创建一个方法特殊器,而不是函数。本质上假设一种方法是这样定义的:
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
, ,从本质上讲,创建特定对象的按需拦截其插槽写作。 (目的是记录旧插槽值的位置,然后调用下一个方法。)我不想创建一个元素,因为我可能想拦截已经实例化的标准对象。
我当然尝试过,但它不起作用(因为您如何 DEFMETHOD
在一个 LABELS
?)但是我希望一些经验丰富的人能够以这种方式验证它无法解决和/或提出合适的方式。
注释?
编辑:
丹尼尔(Daniel)和特耶(Terje)提供了良好的链接,以扩大我对可能性的知识,但我想在去那里之前更多地搜索更多的香草方法。我一直在考虑进入环境时进行添加方法,这将专门研究EQL,并在退出时执行删除方法。我还没有完成。如果有人玩过这些,评论会很好。将使线程保持最新。
编辑2:我几乎可以使用添加方法方案进行操作,但是存在问题。这是我尝试的:
(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)
)))
用某些对象插槽和数据呼叫(my检验),如ARG所致:
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特殊化:方法后,但不幸的是,它似乎没有被调用。谁能提供帮助,以便我可以完成它并将其重构为一个甜美的小实用宏?
解决方案
不,您不能在通用LISP中定义动态范围或词汇范围的专业方法。
面向方面的编程 可以用作解决潜在问题的方法。也可以看看 面向上下文的编程.
contextl 是一个为普通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提出的特殊表格,但已从最终规格中删除,因为它被认为很少受到实施和设计不佳的支持。看 问题通用的漏气设计的写入 在Hyperspec中。有趣的是,阅读讨论为什么人们认为词汇方法不如词汇范围的功能有用。
因此,没有这些,我真的不会认为可以创建词汇范围的方法,尽管我没有使用Terje在另一个答案中链接到的Contectl,因此可能会提供您需要的东西。