gpt4 book ai didi

common-lisp - Common Lisp 如何推送到返回的列表?

转载 作者:行者123 更新时间:2023-12-01 01:46:47 25 4
gpt4 key购买 nike

假设我有一个列表变量 *test*设置为 (:v1 (1) :v2 (2))
然后,在一些字符串配对之后,我需要添加另一个 1:v1 ,相当于:

(push 1 (getf *test* :v1))

但是,它看起来更像:
(push 1 (getf-string-equal *test* "v1"))

getf-string-equal 在哪里(取自 here )
(defun getf-string-equal (plist indicator)
(loop
for (i v) on plist by #'cddr
when (string-equal i indicator)
return v))

但是,我的问题是我不能使用 setf在返回的列表中。我可以使用一些丑陋的技巧来插入函数内部的副作用,但我试图避免这种情况。

如何修改通过将属性作为字符串搜索而获得的列表属性?相当于:
(push 1 (getf-string-equal *test* "v1"))

谢谢。

最佳答案

注意:这个答案不是一个完整的解决方案,因为它不处理找不到 key 的情况。它只是为您指明正确的方向。

这个问题有几个层次。首先,push是一个或多或少扩展为 setf 的宏称呼。因此,我们需要定义一个 setf扩展为 getf-string-equal .这很容易用一个小复杂来完成。

(defsetf getf-string-equal (plist indicator) (value)
(let ((i (gensym))
(rest (gensym))
(match (gensym)))
`(let ((,match (loop
for (,i . ,rest) on ,plist by #'cddr
when (string-equal ,i ,indicator)
return ,rest)))
(if ,match
(setf (car ,match) ,value)
nil))))

让我们分解一下。我们正在使用 defsetf 的长格式为我们的函数定义一个扩展。 plistindicator是参数,和之前一样, value是要分配的新值。但这不是一个函数;它更接近一个宏。所以我们要生成一些代码。为此,我们需要一些 gensym调用以获取一些临时变量。

接下来,我们生成运行您在访问器中使用的相同循环的代码。这里的区别在于,我们将返回包含它的 cons 单元格,而不是返回实际值。这样,我们可以设置 car在那个单元格中并产生实际修改数据结构的效果。如果找到匹配项,我们就这样做,我们就完成了。

但是,如果找不到匹配项,就会出现问题。如果没有这样的 cons单元格,我们不可能设置它的 car .这是本文中的第二种情况 if .我们想简单地扩展到 `(setf ,plist ,value) ,这将具有正确的语义。然而, defsetf不会让我们像宏一样访问实际使用的变量。因此,要完全解决这个问题,包括找不到值的极端情况,我们必须深入 define-setf-expander defsetf 的完全通用形式.为了让大家感受一下这个宏的通用性,正确写出 setf使用它扩展,您的扩展必须是一个返回五个不同值的表达式。

关于common-lisp - Common Lisp 如何推送到返回的列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48197428/

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