2009-09-06 3 views
7

Ich bin neu zu lisp und schreibe ein paar einfache Programme, um damit vertrauter zu werden. Eines der Dinge, die ich mache, ist das Schreiben einer rekursiven und iterativen Version einer faktoriellen Methode. Ich bin jedoch auf ein Problem gestoßen und kann es anscheinend nicht lösen.Lisp Warnung: xx ist weder deklariert noch gebunden, es wird behandelt, als ob es SPEZIAL erklärt wurde

sah ich einen ähnlichen Fehler bei Lisp: CHAR is neither declared nor bound aber eine Lösung nicht wirklich erreicht wurde, anders als die OP erkannte, dass er einen „Tippfehler“ gemacht. In der REPL kann ich die setf-Funktion verwenden und es funktioniert gut. Ich benutze auch LispBox mit Emacs. Ich würde mich über Vorschläge freuen!

(defun it-fact(num) 
    (setf result 1) 
    (dotimes (i num) 
    (setf result (* result (+ i 1))) 
) 
) 

WARNUNG in IT-FACT: RESULT weder deklariert noch gebunden, wird sie behandelt werden, als ob es SPECIAL deklariert wurden.

+1

Siehe http://www.cs.cmu.edu/Groups/AI /html/faqs/lang/lisp/part1/faq-doc-4.html, besonders das "GUT:" Beispiel. Die Leute hier sind in beiden Fällen ziemlich freundlich, aber Ihr Code ist leichter zu lesen, wenn er mehr wie typischer Lisp-Code eingerückt ist. Prost! – Alec

Antwort

5

Sie müssen die Variable ‚Ergebnis‘ binden - ‚lassen‘, beispielsweise mit - bevor es zu benutzen beginnen:

(defun it-fact(num) 
    (let ((result 1)) 
    (dotimes (i num) 
     (setf result (* result (+ i 1)))))) 

Für weitere Details, die Sie wollen vielleicht this lesen ...

+0

Oh, ich verstehe. Ich hatte vorher auch 'Let' versucht, aber ich benutzte es, als wäre es setf, und ich hatte die Schleife nicht in die Klammer des Let eingeschlossen. Ich denke, das hat mit dem Umfang oder etwas zu tun. Danke für die Hilfe alle! – Aaron

+0

Ernsthaft, Code richtig einrücken. –

+0

Da ich in erster Linie ein Java-Programmierer bin, können Sie leicht sehen, warum ich die Klammern heruntergebrochen habe (sie als nichts weiter als Klammern zu betrachten). Seitdem habe ich mich daran gewöhnt, die schließenden Eltern aufgrund der hier vorgestellten Beispiele auf eine Linie zu stellen, also ist es "ernsthaft" nicht so groß. Danke anway :) – Aaron

5

In Lisp müssen lokale Variablen explizit mit LET oder anderen Formen deklariert werden, die lokale Variablen erstellen. Das unterscheidet sich von z.B. Python oder JavaScript, wobei die Zuweisung zur Variablen die Variable im aktuellen lexikalischen Bereich erstellt.

Ihr Beispiel kann wie folgt neu geschrieben werden:

(defun it-fact(num) 
    (let ((result 1)) 
    (dotimes (i num) 
     (setf result (* result (+ i 1)))))) 

Ein Wegthema Kommentar: Es gibt keinen Punkt schließende Klammern in separaten Zeilen in Putten.

6

Es gibt ein paar Dinge falsch oder nicht so gut Lisp-Stil:

(defun it-fact(num)      ; style: use a space before (
    (setf result 1)      ; bad: variable result is not introduced 
    (dotimes (i num) 
    (setf result (* result (+ i 1)))  ; bad: extra addition in each iteration 
)          ; style: parentheses on a single line 
)          ; bad: no useful return value 

Eine mögliche Version:

(defun it-fact (num) 
    (let ((result 1))      ; local variable introduced with LET 
    (loop for i from 1 upto num   ; i starts with 1, no extra addition 
     do (setf result (* result i))) 
    result))        ; result gets returned from the LET 
+2

Danke für die Vorschläge! Ja, ich habe gemerkt, dass die Punktzahlen von 0 ausgehen und wenn ich sie nicht in der Multiplikation erhöhen würde, würde sie immer 0 zurückgeben ... Ihre Schleife sieht einfacher aus zu lesen. Ich denke, ich setze Klammern auf jede Zeile, weil ich immer noch Klammern aus C++/Java verwendet, aber ich werde versuchen, Ihre Praxis für Lisp zu übernehmen. Ups, ja, ich habe die Rückkehr übersehen, danke, dass du auf diese Dinge hingewiesen hast! – Aaron