LISP lokale / globale Variablenzuweisung

8

Wenn wir eine Funktion wie

definieren %Vor%

Ist x als lokale Variable oder global definiert? setf / q setzt den Wert auf global. Wenn es global ist, kann mir jemand sagen, wie man eine lokale Variable in Lisp als let definiert?

Danke!

Betrachten Sie das folgende Beispiel

%Vor%

Wenn ich foo like (foo 2) gebe, gibt es 2 zurück und wenn wir die Funktion erneut mit (foo 1) ausführen, gibt es immer noch 2 zurück und (foo 3) gibt 3 zurück. Das ist was ich eigentlich will es tut. Aber die Frage ist, wie ist das möglich, denn wenn ich versuche, auf die Variable x außerhalb der Funktion von der Clisp-Terminal zuzugreifen, kann ich nicht. Wenn ich wieder auf die Funktion zugreifen, scheint es die vorherige beizubehalten Wert von x .

Danke!

    
Sid 08.09.2012, 18:58
quelle

3 Antworten

7

Um eine Parallele zu anderen Sprachen wie C, C ++, Java oder Python zu zeichnen, ist Ihre Codeänderung eine "lokale Variable", auch wenn dies keine Formulierung ist, die ein Lisper verwenden würde (der Wortlaut in Lisp wäre lokal "verbindlich").

Sie können lokale Variablen mithilfe von Funktionsparametern wie in Ihrem Beispiel oder mit Standardformularen wie:

erstellen
  • (let ((x 12)) ...)
  • (do ((x 0 (1+ i))) ...)
  • (dotimes (x 10) ...)
  • (loop for x from 0 to 10 do ...)

Auf der anderen Seite ist es möglich, dass in Ihrer Implementierung alle lokalen Variablen mit Parametern erzeugt werden und andere Formen einfach Makros sind, die sich auf diese erweitern. Zum Beispiel:

%Vor%

entspricht

%Vor%

Beachten Sie auch, dass x in der Tat eine "globale Variable" ist, weil es möglicherweise als speziell deklariert wurde:

%Vor%

Wenn Sie eine Variable "special" mit (defvar ...) deklarieren, wird dies anders gehandhabt: Es ist wie bei jeder Verwendung als Parameter oder in einer (let ..) Form, was der Code tun wird, um den aktuellen zu speichern Geben Sie den neuen Wert ein und stellen Sie den Wert nach dem Beenden der Funktion oder let wieder her.

Also sind diese Variablen sowohl "global" (weil äußere Funktionen sie sehen können) als auch lokal (weil nach Ihrer Funktion oder lassen Sie den vorherigen Wert wird wiederhergestellt werden).

Die Standardkonvention besteht darin, spezielle Variablen mit "Ohrenschützern" zu benennen, d. h. mit einem Stern sowohl am Anfang als auch am Ende des Namens wie:

%Vor%

Dies hilft, wer Ihren Code liest, um zu verstehen, dass die Variable speziell ist. Beachten Sie, dass dies jedoch nicht von der Sprache vorgeschrieben ist und dass jeder Name für eine spezielle Variable verwendet werden kann.

Es gibt nichts, das speziellen Variablen in C, C ++, Java oder Python ähnlich ist.

Eine letzte Anmerkung zu setq und setf . Die Dinge sind ein bisschen schwierig hier, weil Sie niedrigere Ebenen von Lisp verstehen müssen, um zu sehen, warum setq benötigt wird. Wenn Sie Common Lisp verwenden, sollten Sie einfach setq vergessen und immer setf verwenden.

setf ist ein Makro, das bei Bedarf in setq erweitert wird (aber auch setq kann bei Bedarf in setf geändert werden (Symbolmakros) und hier kann es für einen Neuling verwirrend sein).

Ihr letztes Beispiel ist ein Fall einer "Schließung". Wenn Sie eine Funktion definieren (entweder benannt oder unbenannt mit einer (lambda ...) -Form), kann die Funktion die sichtbaren Variablen "erfassen" und später verwenden. Ein einfacher Fall ist oft der "Addierer":

%Vor%

Diese Funktion gibt eine Funktion zurück, die den übergebenen Wert zu einem internen Summierer addiert:

%Vor%

Der Ausgang wird 13 (10 + 3), 22 (13 + 9) und 33 (22 + 11) sein.

Die anonyme Funktion "erfasst" die lokale Variable x und kann sie auch nach dem Beenden der Funktion adder verwenden. In Sprachen wie C, C ++ oder Java kann eine lokale Variable nicht überleben, wenn Sie den Bereich beenden, der die Variable definiert hat.

C ++ 11 hat unbenannte Funktionen, aber Variablen können nicht erfasst werden und überleben den Bereich (sie können in lokale Variablen der unbenannten Funktion kopiert werden, aber das ist nicht das Gleiche).

    
6502 08.09.2012, 19:58
quelle
4

Tatsächlich ist x lokal für die Funktion, also ändert setf oder setq nur die lokale Variable x .

Um den zweiten Teil Ihrer Frage zu beantworten, gibt es eine andere Möglichkeit, eine andere lokale Variable als let zu definieren:

%Vor%

Tatsächlich könnte defun als

implementiert werden %Vor%

obwohl alle Implementierungen, die ich überprüft habe, mehr als das tun.

Auch der symbol-function Platz erlaubt Ihnen dies zu tun:

%Vor%

obwohl das im Allgemeinen eine schlechte Idee ist.

Ihre zweite Frage

Was passiert, ist, dass x lokal für den Bereich ist, der defun enthält. Es ist nicht eine globale Variable. Was Sie mit diesem defun machen, ist das Erstellen eines Abschlusses, der alle lexikalischen Bereiche (nicht erstellt mit defvar / defparameter ) Variablen in den umgebenden Bereichen "erfasst" und für die Zukunft festhält. Wenn Sie den Wert von x überprüfen möchten, fügen Sie eine weitere Funktion hinzu

%Vor%

in let . Um es anders auszudrücken: x ist lokal für die let , in der sich die Funktion befindet. Die von Ihnen angegebene Situation ähnelt der folgenden:

%Vor%

außer der innere let wird durch einen defun ersetzt (was ein lambda ist).

    
krzysz00 08.09.2012 19:14
quelle
0

In Ihrem Code ist x ein Parameter für die Funktion f und somit lokal für die Funktion. Der Aufruf von setf erstellt keine neue Variable, sondern setzt einfach den Wert der vorhandenen lokalen Variable x . Die Verwendung von setq anstelle von setf würde sich genauso verhalten.

    
sepp2k 08.09.2012 19:03
quelle

Tags und Links