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

如何修改Lisp的make-stack过程以支持空列表初始化?

支持空列表初始化的栈实现

原代码没法用空列表初始化,根源是直接操作传入的列表——空列表不是cons单元格,没法执行car、set-car!或set-cdr!这类操作。换个思路,用一个容器把栈内容包起来,就能解决这个问题:

(define (make-stack lst)
  ;; 用单元素列表当容器,存当前栈的实际内容
  (define stack-box (list lst))
  (lambda message
    (case (car message)
      ((see) (newline) (write (car stack-box)))
      ((empty?) (null? (car stack-box)))
      ((push) (let ((new-top (cadr message)))
                ;; 新元素压栈,直接构造新的cons结构当新栈
                (set-car! stack-box (cons new-top (car stack-box)))))
      ((pop) (if (null? (car stack-box))
                 (error "空栈不能弹出元素")
                 (let ((elt (car (car stack-box))))
                   ;; 弹出后,栈变成原栈的剩余部分
                   (set-car! stack-box (cdr (car stack-box)))
                   elt))))))

核心改动

  • 新增stack-box容器:不管栈空不空,这个容器都是有效的cons单元格,能安全执行set-car!操作
  • push操作直接用cons构造新栈,替代原代码里绕弯的手动修改逻辑(原逻辑在空栈时直接失效)
  • pop操作先检查栈是否为空,避免报错;弹出逻辑更直观,直接取栈顶、更新栈为剩余元素
  • 所有访问栈内容的地方都指向容器里的(car stack-box),统一操作入口

测试示例

现在可以放心用空列表初始化了:

;; 空栈初始化
(define s (make-stack '()))
(s 'empty?) ; 输出 #t

;; 压入元素
(s 'push 10)
(s 'push 20)
(s 'see) ; 输出 (20 10)

;; 弹出元素
(write (s 'pop)) ; 输出 20
(newline)
(s 'see) ; 输出 (10)

(write (s 'pop)) ; 输出 10
(newline)
(s 'empty?) ; 输出 #t

;; 空栈弹出会报错
;; (s 'pop) ; 提示:空栈不能弹出元素

原代码失效原因

原代码的push试图直接修改传入列表的cdr,把原列表改成(新元素 原元素 . 原cdr)的结构——这其实是手动模拟cons,但如果传入的是空列表:

  • set-cdr!会报错,因为空列表不是cons单元格,没法修改它的cdr
  • pop时取(car lst)也会报错,因为空列表没有car

用容器封装后,我们操作的始终是容器里的栈内容,彻底避开了空列表的操作限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 17:23:10