gpt4 book ai didi

common-lisp - 如何让自引用绑定(bind)?

转载 作者:行者123 更新时间:2023-12-04 02:46:11 27 4
gpt4 key购买 nike

我有一个 let我需要其中一个绑定(bind)在正文中引用它自己。即我需要这样的东西:

(let ((my-value (make-value :some-data 2784 :next-value my-value)))
; ...)

这失败了,因为 my-value在定义是不受约束的。我想我也许可以使用 setf分配值,但这对我来说不是一个好的通用解决方案(例如,由于副作用)。

我该如何处理这种情况?也许有一种方法可以进行前向声明?

最佳答案

I think I might be able to use setf to assign the value but it's not a good general solution for me (e.g. because of side-effects).



某些语言旨在支持自引用变量,例如代数系统,您可以在其中编写 x = x * 4 - 2系统求解 x 的方程.
在 Common Lisp 中,评估规则说您必须能够评估 xmake-value 的论点中在能够为 x 分配有意义的值之前.

您可以使用 lambda 延迟操作.例如,您可以添加 lazy-let宏会改变这个:
(lazy-let ((x (make-value :some-data d :next-value x)))
...)

...进入那个:
(let* ((x0 nil)
(x (make-value :some-data d :next-value (lambda () x0))))
(setf x0 x)
...)

但是你需要强制计算惰性值,使用 funcall .像 Haskell 这样的惰性语言会为您隐藏这种行为。

如果你在 Prolog 中写作,你会说:
make_value(X,D) :- X = value{data: D, next: X}.

这要归功于统一,它可以用来执行一种有趣的副作用,即最多设置一次变量。
然而,这在 Common Lisp 中是不可能的(你可以在 Lisp 中实现统一,但如果唯一的目的是避免 setf ,你可能不应该这样做)。

上述示例中发生的情况是隐藏了副作用。
我的观点是,没有什么魔法:不知何故,必须有一个副作用来建立一个对象和它自己之间的链接,即使它不可见。

您可以做同样的事情并在本地执行副作用的实现上提供无副作用的功能。这是完全可以接受的。
首先,定义你的类型:
(defstruct (value (:constructor make-value%))
some-data
next-value)

基本构造函数名为 make-value% , 一个可能不应该由您的包导出的名称。然后,定义面向用户的构造函数:
(defun make-value (&key some-data (next nil nextp))
(let ((value (make-value% :some-data some-data)))
(setf (value-next-value value) (if nextp next value))
value))

该实现小心地将本地副作用包装到一个函数中,从外部角度来看,它不会改变其环境(备注:分配内存也是一个副作用)。它允许用户提供下一个元素,但默认情况下它将结构链接到自身。
这是一个示例用法:
(let ((x (make-value :some-data 1234)))
(assert (eq x (value-next-value x))))

关于common-lisp - 如何让自引用绑定(bind)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37600820/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com