2016-07-19 11 views
0

Wenn ich meinen Code ausführen, sagt es, dass es eine nicht gebundene Variable in meiner Funktion Fill-Lib, aber ich habe keine Ahnung, welche Variable nicht gebunden ist oder warum.Nicht gebundene Variable in Lisp

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

Sie scheinen 'COND' mit' IF' zu verwechseln. – Barmar

+1

Ich bin sicher, die Fehlermeldung sagt, welche Variable nicht gebunden ist. – Barmar

+1

Sie sollten lernen, lokale Variablen mit 'LET' zu verwenden und globale Variablen nicht mit' SETQ' zuzuweisen. – Barmar

Antwort

2

Die cond speziell für die abstrakte Syntax (cond (<test> [<form> ...])...). Das heißt, jede "Aussage" oder "Test" muss eine Liste sein, beginnend mit einem Testformular. Wenn die Testform nicht nil ist (das ist im Wesentlichen Common Lisp für "true"), werden die Folgeformen in einer "implicit prog" (im Grunde "Codeblock") ausgewertet. Wenn es keine Folgeformen gibt, wäre der Rückgabewert der Wert des Testformulars. Wenn es Null ist (Common Lisp für "false"), wird der nächste Test auf die gleiche Weise ausgewertet.

Sie haben (cond (> count 1) (return (princ "Library filled"))), ist dies eine cond Form mit zwei Formen, die erste (> count 1) zu sein, die als „interpretiert wird, wenn die Variable > nicht-Null ist, erste count bewerten, dann 1 auswerten und das Ergebnis davon lassen zuletzt sei das Ergebnis der Cond Form ".

Es wäre (wahrscheinlich) gelöscht, wenn Sie when anstelle von cond hier, da (when (> count 1) (return (princ "Library filled"))) tun würde, was ich nur annehmen, können Sie (print „Bibliothek gefüllt“ und bringe diese Zeichenfolge von der Funktion) tun wollen.

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

So haben Sie 5 Standorte, wo Sie mit nicht gebundenen Variablen arbeiten.

Für die ersten drei: nicht setf ungebundenen Variablen. Verwenden Sie defparameter oder defvar auf der obersten Ebene, wenn Sie eine global spezielle Variable einführen möchten. Verwenden Sie let, let* oder multiple-value-bind für neue lokale Bindungen (oder Funktion Parameter oder do Schleifen ...).

Für die beiden anderen: cond nimmt Klauseln, die eine Bedingung Form als erste Element und einem Körper als Ruhe haben, so müsste es sein:

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

Für conditionals mit besser nur eine Klausel when verwenden :

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

Verbesserte 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."))