You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求可遍历defstruct的Common Lisp subst变体(支持SBCL)

实现支持结构体的通用深层替换函数

标准subst仅会遍历列表和原子类型,无法深入结构体、数组等复合类型内部进行替换。针对SBCL环境,我们可以实现一个递归遍历所有常见Lisp对象类型的深层替换函数,满足你的需求:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (require :sb-mop))

(defun deep-subst (new old tree &key (hash-table-handle :values) (include-clos-objects t))
  "递归替换树中所有出现的OLD为NEW,支持列表、数组、结构体、哈希表等类型。
HASH-TABLE-HANDLE可选值: :values (只替换值)、:keys (只替换键)、:both (替换键和值)
INCLUDE-CLOS-OBJECTS为T时,也递归处理CLOS实例的槽"
  (cond
    ;; 匹配目标值,直接替换
    ((eql tree old)
     new)
    ;; 处理列表/cons
    ((consp tree)
     (cons (deep-subst new old (car tree)
                       :hash-table-handle hash-table-handle
                       :include-clos-objects include-clos-objects)
           (deep-subst new old (cdr tree)
                       :hash-table-handle hash-table-handle
                       :include-clos-objects include-clos-objects)))
    ;; 处理数组(含向量)
    ((arrayp tree)
     (let* ((dimensions (array-dimensions tree))
            (new-array (make-array dimensions
                                   :element-type (array-element-type tree)
                                   :adjustable (adjustable-array-p tree)
                                   :fill-pointer (when (array-has-fill-pointer-p tree)
                                                   (fill-pointer tree)))))
       (dotimes (i (array-total-size tree) new-array)
         (setf (row-major-aref new-array i)
               (deep-subst new old (row-major-aref tree i)
                           :hash-table-handle hash-table-handle
                           :include-clos-objects include-clos-objects)))))
    ;; 处理结构体
    ((structurep tree)
     (let ((copy (copy-structure tree)))
       (loop for slot in (sb-mop:class-slots (class-of tree))
             for slot-name = (sb-mop:slot-definition-name slot)
             do (setf (slot-value copy slot-name)
                      (deep-subst new old (slot-value tree slot-name)
                                  :hash-table-handle hash-table-handle
                                  :include-clos-objects include-clos-objects)))
       copy))
    ;; 处理CLOS对象(可选开启)
    ((and include-clos-objects (standard-object-p tree))
     (let ((copy (make-instance (class-of tree))))
       (loop for slot in (sb-mop:class-slots (class-of tree))
             for slot-name = (sb-mop:slot-definition-name slot)
             when (slot-boundp tree slot-name)
               do (setf (slot-value copy slot-name)
                        (deep-subst new old (slot-value tree slot-name)
                                    :hash-table-handle hash-table-handle
                                    :include-clos-objects include-clos-objects)))
       copy))
    ;; 处理哈希表
    ((hash-table-p tree)
     (let ((new-hash (make-hash-table :test (hash-table-test tree)
                                      :size (hash-table-size tree)
                                      :rehash-size (hash-table-rehash-size tree)
                                      :rehash-threshold (hash-table-rehash-threshold tree))))
       (maphash (lambda (k v)
                  (let ((new-k (if (or (eq hash-table-handle :keys) (eq hash-table-handle :both))
                                   (deep-subst new old k
                                               :hash-table-handle hash-table-handle
                                               :include-clos-objects include-clos-objects)
                                   k))
                        (new-v (if (or (eq hash-table-handle :values) (eq hash-table-handle :both))
                                   (deep-subst new old v
                                               :hash-table-handle hash-table-handle
                                               :include-clos-objects include-clos-objects)
                                   v)))
                    (setf (gethash new-k new-hash) new-v)))
                tree)
       new-hash))
    ;; 其他原子类型直接返回
    (t tree)))

测试你的示例

CL-USER> (defstruct my-struct slot-1 slot-2)
MY-STRUCT
CL-USER> (deep-subst 'b1 'b (make-my-struct :slot-1 'a :slot-2 'b))
#S(MY-STRUCT :SLOT-1 A :SLOT-2 B1)

这个函数会递归遍历所有嵌套的复合类型,包括结构体的槽、数组元素、哈希表的键/值等,完全满足深层替换的需求。由于使用了SBCL的sb-mop扩展来访问结构体的槽定义,它是SBCL特定的实现,符合你不介意编译器特定方案的要求。

内容的提问来源于stack exchange,提问作者fakedrake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 23:48:12