在common lisp中,如何覆盖/更改特定类型对象的求值行为?

在common lisp中,如何覆盖/更改特定类型对象的求值行为?,lisp,common-lisp,eval,Lisp,Common Lisp,Eval,在common lisp中,我想实现一种参考系统,如下所示: 假设我有: (defclass引用()((主机)(端口)(文件))) 我还有: (defun fetch remote value(reference)…,它获取并反序列化lisp对象 我如何干预评估过程,以便在评估引用对象时,获取远程值并再次重新评估以生成最终结果 编辑: 更详细地描述我想要实现的目标: 我使用cl-store序列化lisp对象,并将它们发送到要保存的远程文件(或db或任何文件)。成功存储后,我将主机、端口和文件保存

在common lisp中,我想实现一种参考系统,如下所示:

假设我有:

(defclass引用()((主机)(端口)(文件)))

我还有:

(defun fetch remote value(reference)…
,它获取并反序列化lisp对象

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

编辑:

更详细地描述我想要实现的目标:

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

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


我想截取符号的求值,这样当它们的值是引用类型的对象时,就不用返回对象作为符号求值的结果,而是返回(获取远程值对象)的结果了?

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

然而,现在事情变得相当神秘;变量不再是变量,而是神奇的符号,看起来就像变量。例如,无法修改此宏“绑定”的变量的内容。使用这种方法,您所能做的最好的事情就是为
获取aux
提供一个
setf
扩展,它修改了原始位置。

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

尽管库为您提供了部分方法,CommonLisp没有提供一种可移植的方法来实现完全透明的持久值。延迟值或持久值仍然必须显式地进行设置


但是,可以使用slot值透明地强制实现惰性或持久性对象。需要对通用Lisp实现的内部进行更改才能提供一般的透明性,因此您可以使用
p
来执行例如
(+p5)
,其中
p
可能包含持久值或延迟值。

不可能直接更改求值机制。你需要为你的代码编写一个编译器来编译其他东西。一种嵌入式语言

在CLOS级别上,有几种方法可以解决此问题:

两个例子:

  • 编写在引用对象上分派的函数:

    (定义方法移动((对象参照)位置) (移动(取消引用)位置)

    (定义方法移动((对象汽车)位置) (……))

这会变得难看,可能会通过宏自动执行

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

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


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

您能详细介绍一下普通闭包解决方案吗?我在问题中添加了一个更详细的问题描述“调用ref的结果只是一个值;无论其类型如何,都不会考虑进行评估“:当然,但如果我们可以将其放入eval过程中,那么如果有人将该值绑定到var或隐式调用它,它将自动获取并由计算器解析。无论如何,你的建议非常有帮助,但我希望有一种方法可以将引用类型的特殊处理注入到评估的VAIN中。我想用一种更抽象的方式来看待它:in(+p5),p可以是对任意对象的引用,因此其值可以是内存地址中的值或方案获取的资源中的任何值。Lazy或eager与引用或表达式的值所在的位置正交。Lazy或eager定义何时获取表达式或引用的值。我希望能够控制从何处获取表达式的值,或者以某种方式专门计算引用类型上的表达式,或者截取它们的结果。我知道该语言不提供完全透明的持久值的可能性。我只是想知道:1.改变一个实现以使其支持完全透明和解耦的值持久性有多困难。2.值得吗?我的意思是,从这样的事情中会有什么好处,足以证明这种尝试是正当的吗?