GNU CLISP中的堆栈溢出(&不在SBCL中)

mwa*_*wal 1 clisp common-lisp

我在以下代码中出现堆栈溢出,然后在SBCL中尝试了一下并成功了。想知道是什么造成了那里的差异。

特别是:虽然我确实计划在某个时候移至SBCL,但可以在CLISP中使用它吗?

(defvar *objs* nil)                                 ; [1]

(defun parents (obj) (gethash :parents obj))

(defun obj (&rest parents)                          ; [2]
  (let ((obj (make-hash-table)))
    (push obj *objs*)
    (setf (parents obj) parents)
    obj))

(defun (setf parents) (val obj)                     ; [3]
  (prog1 (setf (gethash :parents obj) val)
         (make-precedence obj)))

(defun make-precedence (obj)                        ; [4]
  (setf (gethash :preclist obj) (precedence obj))
  (dolist (x *objs*)
    (if (member obj (gethash :preclist x))
        (setf (gethash :preclist x) (precedence x)))))

(defun precedence (obj)                             ; [5]
  (delete-duplicates (traverse obj)))

(defun traverse (x)                                 ; [6]
  (cons x (mapcan #'traverse (gethash :parents x))))

;; [1] We'll store a list of objects we create in *obj*.
;; [2] Function to create an object, called like (setf scoundrel (obj)).
;; [3] Set an objects (multiple) parents & rebuild precedence list for all affected objs.
;; [4] Rebuild precedence list for obj, then for all affected objs.
;; [5] Returns a list of object and all its ancestors in precedence order as we define it.
;;     (Can read it like (-> obj traverse delete-duplicates) if it helps)
;; [6] Cons an object to all its parents recursively; depth first search.
;;     I pulled this out of labels in precedence above it for clarity & testability.
;; Source: PG's ANSI Common Lisp, Chapter 17, "Example: Objects".
Run Code Online (Sandbox Code Playgroud)

示例-SBCL

(setf scoundrel (obj))
; #<HASH-TABLE :TEST EQL :COUNT 2 {1001A01893}>
(setf sc2 (obj scoundrel))
; #<HASH-TABLE :TEST EQL :COUNT 2 {1001A1F153}>
*objs*
; (#<HASH-TABLE :TEST EQL :COUNT 2 {1001A1F153}>
;  #<HASH-TABLE :TEST EQL :COUNT 2 {1001A01893}>)
(parents scoundrel)
; NIL
; T
(parents sc2)
; (#<HASH-TABLE :TEST EQL :COUNT 2 {1001A01893}>)
; T
Run Code Online (Sandbox Code Playgroud)

示例-GNU CLISP

(setf scoundrel (obj))
;; - Lisp stack overflow. RESET
*objs*
;; - Lisp stack overflow. RESET
Run Code Online (Sandbox Code Playgroud)

值得一提的是,我还没有研究lisp 的双重解释和编译性质。到目前为止,我只是将其用作解释语言。通过将上述功能粘贴到剪辑副本中。

因此,我怀疑编译所有这些功能可能是要考虑的一件事。我注意到我们可以compilecompile-file,我看不出它编译所有用户定义的函数,虽然运营商。

Bru*_*ble 6

默认情况下,GNU CLISP打印哈希表的内容。在您的情况下,它包含圆形结构。

  • 设置*PRINT-CIRCLE*为T 均可启用打印圆形结构而不会引起堆栈溢出。
> (setq *print-circle* t)
T
> *objs*
(#1=#S(HASH-TABLE :TEST FASTHASH-EQL (:PRECLIST . (#1#)) (:PARENTS . NIL)))
Run Code Online (Sandbox Code Playgroud)
  • 或将*PRINT-ARRAY*和设置*PRINT-READABLY*为NIL,以禁止打印哈希表的内容。
> (setq *print-circle* nil *print-array* nil *print-readably* nil)
NIL
> *objs*
(#<HASH-TABLE :TEST FASTHASH-EQL :COUNT 2 #x000335098D40>)
Run Code Online (Sandbox Code Playgroud)