在common-lisp中,我想实现一个参考系统,如下所示:
假设我有:
(defclass reference () ((host) (port) (file)))
我也有:
获取并反序列化lisp对象的(defun fetch-remote-value (reference) ...)。
我如何干预评估过程,以便每当评估引用对象时,都会再次获取并重新评估远程值,以生成最终结果?
编辑:
更详细地描述我想要实现的目标:
使用cl-store,我序列化lisp对象,并将它们发送到远程文件(或db或其他任何文件)进行保存。在成功存储后,我将主机、端口和文件保存在一个引用对象中。我希望,每当在引用对象上调用eval时,首先检索对象,然后对检索到的值调用eval。由于引用也可以在其他(父)对象或聚合类型中序列化,因此我可以通过modyfing eval获得免费的递归远程引用解析,这样我就不必自己遍历和解析已加载对象的子引用。
编辑:由于对象总是对自己求值,所以我的问题有点不对劲。从本质上讲,我想做的是:
我想截取符号的求值,以便当它们的值是引用类型的对象时,返回(fetch-remote-value object)的结果,而不是返回对象作为符号求值的结果。
发布于 2011-06-02 18:56:38
简而言之:您不能这样做,除非重写函数eval并修改Lisp的编译器。评估规则是固定的Lisp标准。
在阅读完扩充的问题后编辑,我不认为你可以在这里完全透明地引用你的参考资料。在像这样的场景中
(defclass foo () (reference :accessor ref))
(ref some-foo)调用ref的结果只是一个值;无论其类型如何,都不会考虑对其进行计算。
当然,您可以通过某种方式定义您的访问器,它可以透明地完成解析:
(defmacro defresolver (name class slot)
`(defmethod ,name ((inst ,class))
(fetch-remote-reference (slot-value inst ',slot))))
(defresolver foo-reference foo reference)编辑您可以(某种程度上)使用符号宏挂接到Common Lisp的符号解析机制:
(defmacro let-with-resolution (bindings &body body)
`(symbol-macrolet ,(mapcar #'(lambda (form) (list (car form) `(fetch-aux ,(cadr form)))) bindings) ,@body))
(defmethod fetch-aux ((any t)) any)
(defmethod fetch-aux ((any reference)) (fetch-remote-reference any))然而,现在事情变得相当神秘;变量不再是变量,而是神奇的符号,只是看起来像变量。例如,不能修改此宏“绑定”的变量的内容。对于这种方法,您能做的最好的事情就是为fetch-aux提供一个setf扩展,它会修改原来的位置。
发布于 2011-06-03 05:06:04
尽管用于lazy evaluatione和object persistence的库给您带来了一部分好处,但Common Lisp并没有提供一种可移植的方式来实现完全透明的持久化值。惰性或持久化值仍然必须显式为forced。
但是,MOP可以用来实现惰性或持久性对象,并透明地强制使用槽值。它需要改变Common Lisp实现的内部结构来提供一般的透明性,所以你可以在p中潜在地保持持久值或惰性值的情况下使用(+ p 5)。
发布于 2011-06-05 16:02:34
不可能直接更改评估机制。你需要为你的代码编写一个编译器。一种嵌入式语言。
在CLOS级别上,有几种方法可以处理它:
两个例子:
(defmethod move ((对象引用)位置) (move (取消引用引用)位置))
(defmethod move ((对象汽车)位置) ...))
这会变得很难看,并且可能是通过宏自动完成的。
CLOS对象已经具有间接性,因为它们可以更改它们的类。即使他们可能改变他们的班级,他们仍然保持他们的身份。CHANGE-CLASS正在破坏性地修改实例。
这样就可以传递引用对象,并在某个时刻加载数据,将引用对象更改为其他类,并相应地设置槽。这种更改类的操作需要在代码中的某处触发。
自动触发它的一种方法可能是一个错误处理程序,它可以捕获涉及引用对象的某些类型的错误。
https://stackoverflow.com/questions/6213455
复制相似问题