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!
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:
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":
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).
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
obwohl alle Implementierungen, die ich überprüft habe, mehr als das tun.
Auch der symbol-function
Platz erlaubt Ihnen dies zu tun:
obwohl das im Allgemeinen eine schlechte Idee ist.
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
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:
außer der innere let
wird durch einen defun
ersetzt (was ein lambda
ist).
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.
Tags und Links lisp common-lisp