Common lisp 修改结构的副本';Lisp中的s字段/插槽

Common lisp 修改结构的副本';Lisp中的s字段/插槽,common-lisp,sbcl,Common Lisp,Sbcl,我正在尝试修改结构字段的副本。我尝试使用COPY-TREE,但没有成功。这是我的密码: (解构场景) (电路板“():类型列表) (字母“”:键入字符串) (空白字符\类型字符) (DEF参数*scen-1* (制作场景) :board(字符串->board“cat----a----b----”) SETFing之前: (打印*scen-1*) #S(场景) :电路板(“A类----”B类----) :字母“” :BLANK-CHAR#\-) 当我试图用复制树修改线路板副本时,它会修改原始线

我正在尝试修改结构字段的副本。我尝试使用
COPY-TREE
,但没有成功。这是我的密码:

(解构场景)
(电路板“():类型列表)
(字母“”:键入字符串)
(空白字符\类型字符)
(DEF参数*scen-1*
(制作场景)
:board(字符串->board“cat----a----b----”)
SETF
ing之前:

(打印*scen-1*)
#S(场景)
:电路板(“A类----”B类----)
:字母“”
:BLANK-CHAR#\-)
当我试图用
复制树
修改线路板副本时,它会修改原始线路板

(let((板(复制树(场景板*scen-1*)))
(setf(第Q子节(第1委员会)02)“GG”))
(打印*scen-1*)
#S(场景)
:电路板(“CAT--”GG--“B--”)
:字母“”
:BLANK-CHAR#\-)
*scen-1*
应保持不变


如何修改
字段的副本,而不是原始字段?谢谢

问题在于
复制树
复制列表结构,但不复制列表的元素。您实际上不需要在此处复制树,因为要复制的列表是平面的

一种修复方法是编写一个函数,用另一个字符串中的字符替换字符串副本中的字符,然后在原始
板的副本中替换所需的
元素。下面是一个执行子字符串替换的函数:

;;; Writes the characters from NEW to OLD starting from START.
(defun replace-substring (old start new)
  (let ((result (copy-seq old)))
    (loop for replacement across new
          for i from start below (+ start (length new))
          do (setf (elt result i) replacement)
          finally (return result))))
下面是一个函数,它通过更新
board
字段的一个字符串元素的副本来更新该字段的副本:

;;; Creates a copy of the BOARD field with the Nth string replaced
;;; by a copy which has had the characters starting from POS
;;; replaced by the characters from NEW.
(defun update-board (board n pos new)
  (let ((new-board (copy-list board))
        (new-seq (replace-substring (nth n board) pos new)))
    (setf (nth n new-board) new-seq)
    new-board))
样本交互:

CL-USER>*scen-1*
#(场景:电路板(“cat----”a----“b----):字母“:BLANK-CHAR \-)
CL-USER>(更新板(场景板*scen-1*)10“gg)
(“猫——”“gg——”“b——”
CL-USER>*scen-1*
#(场景:电路板(“cat----”a----“b----):字母“:BLANK-CHAR \-)

作为上述答案的替代方法,我发现
MAPCAR
COPY-SEQ
可用于执行字符串列表的“深度复制”

(let((图板(mapcar#拷贝序列(场景图板*scen-1*))
等

这也起到了同样的作用。

可能
alexandria:copy sequence
也一样(“缺失”函数在alexandria中经常出现)。