Common Lisp `case` на` read` с пользовательским пакетом - PullRequest
0 голосов
/ 18 июня 2020

Следующий код из OnLisp Пола G работает нормально, если я запускаю его в REPL без специального пакета. Когда я определяю пакет и использую его с (in-package :mypackage), он не работает - он всегда принимает регистр t в операторе case:

(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)))))

1 Ответ

5 голосов
/ 18 июня 2020

Прежде всего имейте в виду, что то, что вы делаете, безумно опасно: неограниченные вызовы read могут заставить программу выполнить любой код . Если вы должны вызывать read для ввода данных пользователем, вызывайте его безопасным способом:

(with-standard-io-syntax
  (let ((*read-eval* nil)
        (*package* ...))
    (read)))

Во-вторых, сделайте отступ в коде, чтобы люди могли его прочитать:

(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)))))

И теперь мы можем аннотировать ваш код (добавляя минимальные read -определения, пока мы на нем), чтобы показать вам, в чем заключается ошибка:

(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))))))

Что вы собираетесь делать find заключается в том, что пакет символа, который вы прочитали, не совпадает с пакетом символа, с которым вы его сравниваете, поэтому символы разные.

...