Unbound variable in Lisp

variables lisp common-lisp

994 просмотра

2 ответа

1 Репутация автора

When I run my code it says that there is an unbound variable in my fill-lib function, but I have no clue what variable is unbound or why.

(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)))))
Автор: plzHelp Источник Размещён: 19.07.2016 08:20

Ответы (2)


2 плюса

17111 Репутация автора

The cond special for has the abstract syntax (cond (<test> [<form> ...])...). That is, each "statement" or "test" needs to be a list, starting with a test form. If the test form is non-nil (that's essentially Common Lisp for "true"), the consequent forms are evaluated in an "implicit progn" (basically "code block"). If there are no consequent forms, the return value would be the value of the test form. If it is nil (Common Lisp for "false"), the next test is evaluated in the same manner.

You have (cond (> count 1) (return (princ "Library filled"))), this is a cond form with two forms, the first being (> count 1), which will be interpreted as "if the variable > is non-nil, first evaluate count, then evaluate 1 and let the result of that last be the result of the cond form".

It would (probably) be cleared if you used when instead of cond here, since (when (> count 1) (return (princ "Library filled"))) would do what I can only assume you want to do (print "Library filled" and return that string from the function).

Автор: Vatine Размещён: 19.07.2016 09:00

1 плюс

43247 Репутация автора

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

So, you have 5 locations where you are working with unbound variables.

For the first three: do not setf unbound variables. Use defparameter or defvar at the top level, if you want to introduce a globally special variable. Use let, let*, or multiple-value-bind for new local bindings (or function parameters, or do loops ...).

For the other two: cond takes clauses that have a condition form as first element and a body as rest, so it would have to be:

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

For conditionals with only one clause better use when:

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

Improved code:

(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."))
Автор: Svante Размещён: 19.07.2016 06:50
32x32