Lisp中的未绑定变量

时间:2016-07-19 08:20:44

标签: variables lisp common-lisp

当我运行我的代码时,它说我的fill-lib函数中有一个未绑定的变量,但我不知道哪个变量是未绑定的或为什么。

(defstruct book 
  (title nil)
  (author nil)
  (genre nil))

(setf b (make-book))
(setf lib ())

(defun fill-lib ()
  (setq count 1)
  (with-open-file (s-stream "/Users/David/Desktop/Books.txt"
                            :direction :input)
    (loop
     (cond (> count 1) (return (princ "Library filled")))
     (setf b (make-book))
     (setf (book-title b) (read-line s-stream))
     (setf (book-author b) (read-line s-stream))
     (setf (book-genre b) (read-line s-stream))
     (setf lib (cons b lib))
     (setq count (+ count 1)))))

2 个答案:

答案 0 :(得分:2)

cond special for具有抽象语法(cond (<test> [<form> ...])...)。也就是说,每个&#34;声明&#34;或&#34;测试&#34;需要是一个列表,从测试表单开始。如果测试形式是非零的(对于&#34而言基本上是Common Lisp;真的&#34;),那么后续的形式将在一个隐含的预测中进行评估。 (基本上是&#34;代码块&#34;)。如果没有结果形式,则返回值将是测试表单的值。如果它是nil(Common Lisp for&#34; false&#34;),则以相同的方式评估下一个测试。

您有(cond (> count 1) (return (princ "Library filled"))),这是一个cond表单,其中包含两种表单,第一种是(> count 1),如果变量>将被解释为&#34}是非零的,首先评估count,然后评估1并让最后的结果成为cond形式的结果&#34;。

如果你在这里使用when代替cond,那么(可能)会被清除,因为(when (> count 1) (return (princ "Library filled")))会做我只能假设你想做的事(打印&#34;库已填充&#34;并从函数中返回该字符串。

答案 1 :(得分:1)

(defstruct book 
  (title nil)
  (author nil)
  (genre nil))

(setf b (make-book)) ; b is unbound
(setf lib ())        ; lib is unbound

(defun fill-lib ()
  (setq count 1)     ; count is unbound
  (with-open-file (s-stream "/Users/David/Desktop/Books.txt"
                            :direction :input)
    (loop
     (cond (> count 1) (return (princ "Library filled")))  ; > is unbound, return is unbound
     (setf b (make-book))
     (setf (book-title b) (read-line s-stream))
     (setf (book-author b) (read-line s-stream))
     (setf (book-genre b) (read-line s-stream))
     (setf lib (cons b lib))
     (setq count (+ count 1)))))

因此,您有5个位置用于处理未绑定的变量。

对于前三个:不要setf未绑定的变量。使用defparameter或 如果要引入全局特殊变量,则在顶级defvar。 使用letlet*multiple-value-bind进行新的本地绑定(或函数) 参数,或do循环......)。

对于另外两个:cond将条件形式的子句作为第一个 元素和身体作为休息,所以它必须是:

(cond ((> count 1) (return (princ "Library filled"))))

对于只有一个子句的条件,请更好地使用when

(when (> count 1)
  (return (princ "Library filled")))

改进代码:

(defstruct book 
  (title nil)
  (author nil)
  (genre nil))

(defvar *lib* ())

(defun fill-lib (filename count)
  (with-open-file (s-stream filename
                            :direction :input)
    (loop :repeat count
          :for b := (make-book :title (read-line s-stream)
                               :author (read-line s-stream)
                               :genre (read-line s-stream))
          :do (push b *lib*)))
  (princ "Library filled."))
相关问题