Frage

Ich arbeite mich durch Grahams Buch „On Lisp“ und kann nicht verstehen, das folgende Beispiel auf Seite 37:

If we define exclaim so that its return value
incorporates a quoted list,

(defun exclaim (expression)
  (append expression ’(oh my)))

>  (exclaim ’(lions and tigers and bears))
(LIONS AND TIGERS AND BEARS OH MY)
> (nconc * ’(goodness))
(LIONS AND TIGERS AND BEARS OH MY GOODNESS)

could alter the list within the function:

> (exclaim ’(fixnums and bignums and floats))
(FIXNUMS AND BIGNUMS AND FLOATS OH MY GOODNESS)

To make exclaim proof against such problems, it should be written:
(defun exclaim (expression)
  (append expression (list ’oh ’my)))

Hat jemand verstehen, was hier vor sich geht? Dies wird ernsthaft mit meinem mentalen Modell des Schrauben, was unter Angabe des Falles ist.

War es hilfreich?

Lösung

nconc ist eine destruktive Operation dass ändert sein erstes Argument, das von seinem Schwanz zu verändern. In diesem Fall bedeutet dies, dass die ständige Liste '(oh my) einen neuen Schwanz bekommt.

Um hoffentlich dies deutlicher machen. Es ist ein bisschen wie folgt aus:

; Hidden variable inside exclaim
oh_my = oh → my → nil

(exclaim '(lions and tigers and bears)) =
    lions → and → tigers → and → bears → oh_my

(nconc * '(goodness)) destructively appends goodness to the last result:
    lions → and → tigers → and → bears → oh → my → goodness → nil
so now, oh_my = oh → my → goodness → nil

Ersetzen '(oh my) mit (list 'oh 'my) behebt diese, weil es nicht mehr eine Konstante von jedermann geteilt werden. Jeder Aufruf von exclaim eine neue Liste erzeugt (die Zweck der list Funktion im Leben ist brandneu Listen erstellen).

Andere Tipps

Die Beobachtung, dass Ihr mentales Modell zu zitieren fehlerhaft sein kann, ist ein ausgezeichneter ein obwohl es oder möglicherweise nicht zutreffend ist, je nachdem, was die mentale Modell ist.

Zunächst erinnern, dass es verschiedene Stufen der Programmausführung. Ein Lisp-Umgebung muss zunächst lesen der Programmtext in Datenstrukturen (Listen, Symbole und verschiedene wörtliche Daten wie Strings und Zahlen). Als nächstes es kann oder auch nicht Compile diese Datenstrukturen in Maschinencode oder irgendeine Art von Zwischenformat. Schließlich wird der resultierende Code ist Evaluierte (im Falle von Maschinencode, natürlich, das kann einfach bedeuten, Springen an die entsprechende Adresse).

setzen Lassen Sie uns die Frage der Zusammenstellung beiseite für jetzt und konzentrieren sich auf die Lese- und Auswertungsstufen unter der Annahme (der Einfachheit halber), dass die Eingabe des Bewerters die Liste von Datenstrukturen durch den Leser zu lesen.

ein Formular (QUOTE x) Überlegen Sie, wo x ist einige Textdarstellung eines Objekts. Dies kann Symbol wörtlichen wie in (QUOTE ABC), eine Liste wörtlichen wie in (QUOTE (A B C)), ein Zeichenfolgenliteral wie in (QUOTE "abc"), oder jede andere Art von wörtlichen sein. In der Lesephase wird der Leser das Formular als Liste lesen (nennen wir es form1 ), deren erstes Element das Symbol QUOTE und dessen zweites Element ist das Objekt x ', deren Textdarstellung ist x . Beachten Sie, dass ich sage ausdrücklich, dass das Objekt x ' gespeichert ist, in der Liste, die den Ausdruck steht, also in gewissem Sinne ist es gespeichert als einen Teil der Code selbst .

Jetzt ist es an der Reihe des Bewerters. Der Eingang des Bewerters ist form1 , die eine Liste ist. So ist es bei dem ersten Elemente von sieht form1 , und bestimmt hat, dass es das Symbol QUOTE ist, gibt es als das Ergebnis der Auswertung das zweite Element der Liste . Das ist der entscheidende Punkt. Der Evaluator kehrt das zweite Element der Liste ausgewertet werden, was ist das, was der Leser in der ersten Ausführungsstufe lesen (vor der Zusammenstellung!). Das ist alles, es tut. Es gibt keine Magie, um sie, es ist sehr einfach und deutlich, keine neuen Objekte erzeugt werden und keine bestehenden kopiert werden.

Deshalb, wenn Sie eine „zitierte Liste“ ändern, die Sie modifizieren der Code selbst . Selbstmodifizierenden Code eine sehr verwirrende Sache ist, und in diesem Fall wird das Verhalten tatsächlich nicht definiert (weil ANSI Common Lisp-Implementierungen ermöglicht Code in Nur-Lese-Speicher abgelegt werden soll).

Natürlich ist die oben lediglich ein mentales Modell. Implementationen sind frei, das Modell auf verschiedene Weise zu implementieren, und in der Tat, ich kenne keine Implementierung von Common Lisp, die wie meine Erklärung, überhaupt keine Compilation der Fall ist. Dennoch ist dies die Grundidee.

In Common Lisp.

Beachten Sie:

'(1 2 3 4)

Oben ist eine wörtliche Liste . Konstante Daten .

(list 1 2 3 4)

LIST ist eine Funktion, die bei Aufruf gibt eine frische neue Liste mit seinen Argumenten als Listenelemente.

Vermeiden Sie Modifizieren wörtliche Listen. Die Auswirkungen sind nicht standardisiert. Stellen Sie sich ein Lisp, die alle konstanten Daten in einen Schreib kompiliert nur Speicherbereich. Stellen Sie sich ein Lisp, die benötigt konstante Listen und teilt sie über Funktionen.

(defun a () '(1 2 3)

(defun b () '(1 2 3))

Ein Lisp-Compiler kann eine Liste erstellen, die von den beiden Funktionen gemeinsam genutzt wird.

Wenn Sie die Liste von Funktion a

zurück ändern
  • könnte es nicht geändert werden
  • es könnte geändert werden
  • es könnte ein Fehler sein
  • es könnte auch die Liste nach Funktion b zurück ändern

Implementationen haben die Freiheit zu tun, was sie wollen. Dies lässt Raum für Optimierungen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top