在common-lisp中,我如何覆盖/更改特定类型对象的评估行为?

时间:2011-06-02 10:43:24

标签: lisp common-lisp eval

在common-lisp中,我想实现一种这样的参考系统:

假设我有:

(defclass reference () ((host) (port) (file)))

我也有:

(defun fetch-remote-value (reference) ...),用于获取和反序列化lisp对象。

我如何干预评估过程,以便在评估参考对象时,获取远程值并再次重新评估以产生最终结果?

编辑:

对我想要完成的内容进行更详尽的描述:

使用cl-store我序列化lisp对象并将它们发送到要保存的远程文件(或db或任何东西)。成功存储后,我将主机,端口和文件保存在引用对象中。我想,每当在引用对象上调用eval时,首先检索对象,然后对检索到的值调用eval。由于引用也可以在其他(父)对象或聚合类型中序列化,因此我可以通过modyfing eval获得免费的递归远程引用解析,因此我不必遍历并自行解析加载对象的子引用。

编辑: 由于对象总是评估自己,我的问题有点错误。基本上我想做的是:

我想拦截符号的评估,以便当它们的值是REFERENCE类型的对象时,而不是作为符号评估的结果返回对象,以返回(fetch-remote-value object)的结果?

4 个答案:

答案 0 :(得分:2)

简而言之:除了重写函数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))

然而,现在事情变得相当神秘;并且变量不再是变量,而是魔术符号,它们看起来像变量。例如,修改由该宏“绑定”的变量的内容是不可能的。使用此方法可以做的最好的事情是为setf提供fetch-aux扩展,修改原始位置。

答案 1 :(得分:2)

尽管lazy evaluationeobject persistence的库为您提供了部分方法,但Common Lisp并未提供实现完全透明持久值的可移植方法。懒惰或持久值仍然必须明确forced

MOP可用于实现延迟或持久对象,但透明地强制使用插槽值。需要对Common Lisp实现的内部进行更改以提供一般透明度,因此您可以执行以下操作: (+ p 5) p可能持有持久性或惰性值。

答案 2 :(得分:1)

无法直接更改评估机制。您需要为您的代码编写一个编译器。一种嵌入式语言。

在CLOS级别,有几种方法可以解决它:

两个例子:

  • 编写在参考对象上分派的函数:

    (defmethod move((对象引用)位置)    (移动(取消引用参考)位置))

    (defmethod move((对象汽车)位置)    ...))

这很丑陋,可能会使用宏自动化。

CLOS对象已经有间接,因为它们可以更改它们的类。即使他们可能改变他们的阶级,他们仍然保持自己的身份。 CHANGE-CLASS正在破坏性地修改实例。

这样就可以传递引用对象,并在某些时候加载数据,将引用对象更改为其他类并相应地设置槽。需要在代码中的某处触发更改类。

自动触发它的一种方法可能是一个错误处理程序,它可以捕获涉及引用对象的某些错误。

答案 3 :(得分:0)

我会在你的反序列化机制之上添加一个层,根据传入数据的类型进行调度。