带有自定义包的 `read` 上的 Common Lisp `case`

Avi*_*ari 0 lisp user-input sbcl common-lisp package

如果我在没有自定义包的 REPL 中运行它,以下来自 Paul G 的OnLisp 的代码工作正常。当我定义一个包并与它一起使用时(in-package :mypackage)它不起作用——它总是tcase语句中采用这种情况:

(defun run-node (name)
 (let ((n (gethash name *nodes*)))
  (cond ((node-yes n)
         (format t "~A~%>> " (node-contents n))
         (case (read)
           (yes (run-node (node-yes n))) ; never hits this in package
           (t (run-node (node-no n))))) 
        (t (node-contents n)))))
Run Code Online (Sandbox Code Playgroud)

小智 5

首先要知道你在做什么是非常危险的:不受约束的调用read可能会导致程序执行任何代码。如果您必须调用read用户输入,请以安全的方式调用它:

(with-standard-io-syntax
  (let ((*read-eval* nil)
        (*package* ...))
    (read)))
Run Code Online (Sandbox Code Playgroud)

其次,缩进你的代码,以便人们可以阅读它:

(defun run-node (name)
  (let ((n (gethash name *nodes*)))
    (cond ((node-yes n)
           (format t "~A~%>> " (node-contents n))
           (case (read)
             (yes (run-node (node-yes n))) ;never hits this in package
             (t (run-node (node-no n))))) 
          (t (node-contents n)))))
Run Code Online (Sandbox Code Playgroud)

现在我们可以注释您的代码(在read我们处理的时候添加一些最小的-defanging)以向您展示错误是什么:

(defun run-node (name)
  (with-standard-io-syntax
    (let ((n (gethash name *nodes*))
          (*read-eval* nil))
      (cond ((node-yes n)
             (format t "~A~%>> " (node-contents n))
             (let ((got (read)))
               (format *debug-io*
                       "~&*package* ~16T~A~%got package~16T~A~%our package~16T~A~%"
                       (package-name *package*)
                       (typecase got
                         (symbol (package-name (symbol-package got)))
                         (t "(not a symbol"))
                       (package-name (symbol-package 'yes)))
               (case got
                 (yes (run-node (node-yes n))) ;never hits this in package
                 (t (run-node (node-no n))))))
            (t (node-contents n))))))
Run Code Online (Sandbox Code Playgroud)

你会发现你读过的符号包与你比较的符号包不同,所以符号是不同的。