Wie Leben mit Emacs Lisp dynamische scoping?
Habe ich gelernt, Clojure zuvor und mag die Sprache. Ich Liebe auch Emacs und haben gehackt einige einfache Sachen mit Emacs Lisp. Es ist eine Sache, die verhindert, das ich mich mental von etwas mehr erhebliche mit Elisp obwohl. Es ist das Konzept der dynamischen scoping. Ich bin nur erschrocken, da es so Fremd zu mir und riecht wie semi-globalen Variablen.
Also mit Variablendeklarationen ich weiß nicht, welche Dinge sind sicher und welche gefährlich sind. Von dem, was ich verstanden hab, Variablen, die mit setq fallen unter dynamischen scoping (ist das richtig?) Was ist mit let Variablen? Irgendwo habe ich mal gelesen, dass, lassen Sie uns können Sie tun, schlichte lexikalische scoping, aber woanders habe ich gelesen, dass lassen vars auch dynamisch scoped.
Ich quess meine größte Sorge ist, dass mein code (mit setq oder lassen) versehentlich einige Variablen von Plattform-oder third-party-code, dass ich call oder, dass nach einem solchen Anruf meiner lokalen Variablen Durcheinander versehentlich. Wie kann ich diese vermeiden?
Gibt es ein paar einfache Faustregeln, kann ich nur Folgen und genau wissen, was passiert, mit Rahmen, ohne gebissen zu werden, in einigen seltsamen, schwer zu Debuggen Weg?
- Genial Antworten, danke!
- Sehr schöne Frage!
Du musst angemeldet sein, um einen Kommentar abzugeben.
So schlimm ist es nicht.
Die wichtigsten Probleme erscheinen können, mit 'freier Variablen in Funktionen.
In der obigen Funktion
a
ist eine lokale variable.b
ist eine freie variable. In einem system mit dynamischer Bindung wie Emacs-Lisp,b
gesucht bei runtime. Es gibt nun drei Fälle:b
ist nicht definiert -> Fehlerb
ist eine lokale variable gebunden, die durch einige function call in der aktuellen dynamischen Geltungsbereich -> nehmen, dass der Wertb
ist eine Globale variable -> nehmen, dass der WertDie Probleme können dann sein:
In ein Lisp mit einem compiler kompilieren der oben genannten Funktion könnte generieren eine Warnung, dass es eine freie variable. In der Regel Common Lisp-Compiler tun. Ein Dolmetscher wird nicht, die Warnung, man will einfach sehen, die Auswirkungen zur Laufzeit.
Beratung:
*foo-var*
Nicht schreiben
Schreiben:
Binde alle Variablen, die Sie verwenden möchten, und Sie wollen sicherstellen, dass Sie nicht gebunden sind woanders.
Das ist im Grunde es.
Da GNU Emacs version 24 lexikalische Bindung unterstützt Emacs Lisp. Siehe: Lexikalische Bindung, GNU Emacs Lisp Reference Manual.
Gibt es ein paar einfache Faustregeln, kann ich nur Folgen und genau wissen, was passiert, mit Rahmen, ohne gebissen zu werden, in einigen seltsamen, schwer zu Debuggen Weg?
Lesen Emacs Lisp Referenz, aber Sie haben viele details wie dieses :
Diese Besondere form ist die häufigste Methode zum ändern eines
variable Wert. Jedes SYMBOL erhält einen neuen Wert, der der
Ergebnis der Auswertung die entsprechende FORM. Die meisten lokalen
vorhandene Bindung des symbols wird geändert.
Hier ist ein Beispiel :
Zusätzlich zu den im letzten Absatz von Gilles Antwort, hier ist, wie RMS argumentiert zu Gunsten des dynamischen scoping in ein erweiterbares system:
Persönlich denke ich, dass wenn es ein problem mit Emacs-Lisp, es ist nicht dynamische scoping per se, aber es ist der Standard, und, dass es nicht möglich ist, zu erreichen, lexical scoping, ohne auf Erweiterungen. In der CL, dynamische und lexikalische scoping verwendet werden kann, und-mit Ausnahme der obersten Ebene (das ist also von mehreren deflex-Implementierungen), Global und erklärt spezielle Variablen -- der Standard ist lexikalisches scoping. In Clojure, zu, Sie können sowohl lexikalische und dynamischen scoping.
Zitieren RMS wieder:
Als Peter Ajtai hingewiesen:
Da emacs-24.1 können Sie aktivieren, lexikalisches scoping-auf einer pro-Datei basis, indem Sie
oben auf der elisp-Datei.
Erste, elisp hat getrennte variable und Funktion-Bindungen, so einige Fallstricke des dynamischen scoping nicht relevant sind.
Zweitens, können Sie immer noch
setq
zu setzen, Variablen, sondern den Wert nicht überleben Ausgang der dynamische Umfang es getan wird. Dies ist nicht grundsätzlich Verschieden von lexikalischen scoping, mit dem Unterschied, dass mit dynamic scoping eine setq in eine Funktion, die Sie aufrufen können Auswirkungen auf den Wert, den Sie sehen nach dem Aufruf der Funktion.Gibt es
lexical-let
, ein makro, das (im wesentlichen) imitiert lexikalische Bindungen (ich glaube, es tut dies, indem Sie zu Fuß den Körper und ändern Sie alle vorkommen der lexikalisch Variablen lassen sich zu einer gensymmed Namen, schließlich uninterning dem symbol), wenn Sie absolut müssen.Ich würde sagen, "code schreiben als normal". Es gibt Zeiten, wenn die dynamische Natur von elisp wird dich beißen, aber ich habe festgestellt, dass in der Praxis erstaunlich selten.
Hier ist ein Beispiel, was ich sagen über setq und dynamisch gebundene Variablen (bewertete kürzlich in einem nahe gelegenen Kratzer Puffer):
Alles, was hier geschrieben wurde, lohnt sich. Ich würde gerne noch etwas hinzufügen: man weiß Common Lisp -- wenn sonst nichts, darüber zu Lesen. CLTL2 präsentiert lexikalische und dynamische Bindung gut, wie die anderen Bücher. Und Common Lisp integriert Sie gut in einer einzigen Sprache.
Wenn Sie "es bekommen" nach einiger Exposition gegenüber Common Lisp dann werden die Dinge klarer für Sie, für Emacs-Lisp. Emacs 24 verwendet lexikalische scoping zu einem größeren Ausmaß standardmäßig als ältere Versionen, aber Common Lisp Ansatz wird noch klarer und sauberer (IMHO). Schließlich ist es definitiv den Fall, dass der dynamische Umfang ist wichtig für Emacs Lisp, für die Gründe, die RMS und andere haben betont.
Also mein Vorschlag ist, um zu wissen, wie Common Lisp befasst sich mit dieser. Versuchen, zu vergessen, das Schema, wenn das ist Ihre wichtigsten mentalen Modell der Lisp-es wird Grenze, die Sie mehr als Ihnen helfen, zu verstehen scoping, funargs, etc. in Emacs Lisp. Emacs Lisp, wie Common Lisp, "dirty und low-down"; es ist nicht Schema.
Dynamische und lexikalische scoping-haben unterschiedliche Verhaltensweisen, wenn Sie ein Stück code in einem anderen Bereich als dem es definiert wurde. In der Praxis gibt es zwei Muster, die für die meisten beschwerlichen Fällen:
Funktion Schatten eine Globale variable, dann ruft eine andere Funktion verwendet, die Globale variable.
Diese kommen nicht oft in Emacs, weil die lokalen Variablen, neigen zu kurzen Namen (oft einzige-Wort) in der Erwägung, dass Globale Variablen dazu neigen, zu lange Namen haben (oft mit dem Präfix
packagename-
). Viele standard-Funktionen haben Namen, die zu verlockend sind, um den Einsatz als lokale Variablen wielist
undpoint
, aber Funktionen und Variablen, die live im eigenen Namen Räume sind lokal Funktionen sind nicht sehr Häufig verwendet.Einer Funktion definiert ist, in einem lexikalischen Kontext und außerhalb dieser lexikalischen Kontext, weil es an eine übergeordnete Funktion.
Den Fehler aufgrund der Verwendung von
cl-x
als Variablen-Namen in dermapcar*
(aus dercl
- Paket). Beachten Sie, dass diecl
Paket verwendet werdencl-
als Präfix auch für seine lokalen Variablen in higher-order-Funktionen. Dies funktioniert auch Recht gut, in der Praxis, wie lange, wie Sie kümmern sich nicht um die gleiche variable verwenden, als einen globalen Namen und einen lokalen Namen zu, und Sie brauchen nicht zu schreiben Sie eine rekursive higher-order-Funktion.P. S. Emacs Lisp Alter ist nicht der einzige Grund, warum es dynamisch scoped. Stimmt, in diesen Tagen, lisps tendenziell hin zu dynamischen scoping — Scheme und Common Lisp hatte nicht wirklich noch. Aber dynamischen scoping ist auch eine Bereicherung in einer Sprache, die gezielt zur Erweiterung eines Systems dynamisch: Sie können Haken in mehr Orte ohne besonderen Aufwand. Mit großer macht kommt große Seil an sich Aufhängen: Sie riskieren, versehentlich Einhaken in einen Ort, den Sie nicht kannte.
Die anderen Antworten sind gut im erklären der technischen details auf, wie die Arbeit mit dynamischen scoping, also hier ist mein nicht-technische Beratung:
Tun Sie es einfach
Ich habe seit neuestem mit Emacs lisp für 15+ Jahre und nicht wissen, dass ich immer gebissen hat irgendwelche Probleme aufgrund der Unterschiede zwischen den lexikalischen/dynamischen Bereich.
Ich persönlich habe nicht festgestellt, die Notwendigkeit für das Verbot (ich Liebe 'em, nur brauchen Sie nicht für Emacs). Und, ich in der Regel versuchen zu vermeiden, Globale Variablen im Allgemeinen (ob die Festlegung des lösungsumfangs wurde die lexikalische oder dynamisch).
Also ich schlage vor, in springen und schreiben von Anpassungen, die auf Ihre Bedürfnisse/Wünsche, Chancen sind, Sie werden keine Probleme haben.
Ich völlig das Gefühl, Ihre Schmerzen. Ich finde das fehlen der lexikalischen Bindung in emacs eher nervig - vor allem nicht in der Lage, verwenden lexikalische Verschlüsse, das scheint zu sein, eine Lösung, die ich denke, eine Menge, kommen aus der neueren Sprachen.
Während ich habe keine weitere Beratung zu arbeiten, um die fehlenden features, die die vorherigen Antworten nicht decken, doch, ich möchte an dieser Stelle aus der Existenz eines emacs-Zweig namens `lexbind', die Umsetzung lexikalische Bindung in einer rückwärts-kompatiblen Art und Weise. In meiner Erfahrung lexikalische Verschlüsse sind noch ein wenig buggy in einigen Fällen, aber der Zweig scheint ein vielversprechender Ansatz zu sein.
Einfach nicht.
Emacs-24 ermöglicht Ihnen die Verwendung von lexical-scope. Führen Sie einfach
(setq lexical-binding t)
oder fügen Sie
;; -*- lexical-binding: t -*-
am Anfang der Datei.