Können Sie interaktive Funktionen in einem Emacs Lisp-Makro erstellen?

8

Ich versuche ein Makro in emacs lisp zu schreiben, um einige 'Hilfsfunktionen' zu erstellen.

Letztlich werden meine Hilfsfunktionen nützlicher sein als das, was ich hier habe. Ich erkenne, dass es vielleicht bessere / intuitivere Wege gibt, um dasselbe zu erreichen (bitte posten), aber meine grundlegende Frage ist, warum das nicht funktionieren wird / was mache ich falsch:

%Vor%

Wenn ich die Ausgabe des Makroexpands nehme und diese auswerte, bekomme ich die interaktiven Funktionen, die ich mit dem Makro bekommen wollte, aber obwohl das Makro läuft und zu bewerten scheint, kann ich M-x text-ni oder% nicht aufrufen co_de%.

    
Sébastien Le Callonnec 18.03.2009, 23:55
quelle

4 Antworten

10

Das macht, was Sie wollen:

%Vor%     
Trey Jackson 19.03.2009 04:11
quelle
4

Wie bereits erwähnt, besteht die Lösung darin, intern anstelle von make-symbol zu verwenden.

Es ist möglich, mehrere unabhängige Symbole mit demselben Namen zu erstellen, aber nur einer davon kann das kanonische Symbol für den gegebenen Namen sein - dh das Symbol, das Sie erhalten, wenn Sie an anderer Stelle darauf verweisen .

intern gibt das kanonische Symbol für den angegebenen Namen zurück. Es erstellt nur dann ein neues Symbol , wenn bereits ein internes Symbol mit diesem Namen existiert. Dies bedeutet, dass immer nur ein Symbol für einen bestimmten Namen erstellt wird 1 .

make-symbol hingegen erzeugt bei jedem Aufruf ein neues Symbol. Dies sind nicht unterbrochene Symbole - jedes ist ein vollständig gültiges und funktionelles Symbol, aber nicht dasjenige, das zu sehen ist, wenn Sie auf ein Symbol mit seinem Namen verweisen.

Siehe: C-h i g < (elisp) Creating Symbols RET

Da defun das von ihr gesetzte Symbol zurückgibt, können Sie beobachten, was passiert, indem Sie den Rückgabewert erfassen und als Funktion verwenden:

%Vor%

oder ähnlich:

%Vor%

Der knifflige Teil in all dem - und der Grund, warum das Auswerten der expandierten Form das getan hat, was Sie wollten, und doch das Makro nicht - hat mit genau wie und wann (oder in der Tat if ) übersetzt der Lisp-Leser den Namen der Funktion in ein Symbol.

Wenn wir eine Funktion foo1 schreiben:

%Vor%

Der Lisp-Reader liest das als Text und konvertiert es in ein Lisp-Objekt. Wir können read-from-string verwenden, um dasselbe zu tun, und wir können uns die gedruckte Darstellung des resultierenden Lisp-Objekts ansehen:

%Vor%

Innerhalb dieses Objekts ist der Funktionsname das kanonische Symbol mit dem Namen "foo1". Beachten Sie jedoch, dass der Rückgabewert, den wir aus read-from-string sehen, nur die gedruckte Darstellung dieses Objekts ist und das kanonische Symbol nur durch seinen Namen dargestellt wird. Die gedruckte Darstellung erlaubt uns nicht, zwischen internierten und nicht-gebrauchten Symbolen zu unterscheiden, da alle Symbole nur durch ihren Namen dargestellt werden.

(Dies ist die Ursache Ihres Problems, wenn Sie die gedruckte Erweiterung Ihres Makros auswerten, da dieses gedruckte Formular durch den Lisp-Reader geleitet wird und das, was einmal ein nicht-durchgeblendetes Symbol war, wird ein interniertes Symbol.)

Wenn wir dann zu Makros gehen:

%Vor%

Diesmal hat der Leser die -Makro -Definition in ein Lisp-Objekt gelesen, und in diesem Objekt ist das kanonische Symbol% ​​co_de%. Wir können dies überprüfen, indem wir das Objekt direkt untersuchen:

%Vor%

Für dieses Makro hat es also bereits mit diesem kanonischen Symbol% ​​co_de% zu tun, bevor ein Makroaufruf / eine Makroerweiterung stattfindet, weil der Lisp-Leser dies beim Lesen des Makros festgestellt hat. Im Gegensatz zu unserer vorherigen einfachen Funktionsdefinition (in der das Funktionssymbol durch den Lisp-Leser bestimmt wurde, als die Funktion definiert wurde), wenn ein Makro & amp; erweitert der Lisp-Reader wird nicht verwendet. Die Makroerweiterung wird unter Verwendung bereits vorhandener Lisp-Objekte ausgeführt - ein Lesen ist nicht erforderlich.

In diesem Beispiel ist das Funktionssymbol bereits im Makro vorhanden, und weil es das kanonische Symbol ist, könnten wir foo2 an anderer Stelle in unserem Code verwenden, um diese Funktion aufzurufen. (Oder, wenn ich die Definition interaktiv gemacht hätte, verwende foo2 .)

Wenn wir schließlich von der Frage auf das ursprüngliche Makro zurückkommen, ist es offensichtlich, dass der lisp Leser niemals ein Funktionsnamensymbol für die Funktion findet, die definiert werden soll:

%Vor%

Stattdessen enthält dieses vom Lisp-Reader erzeugte Objekt den Ausdruck (foo2) ; und dieser Backquoted-Ausdruck wird zum Zeitpunkt der Expansion ausgewertet, um ein neues Symbol nicht unterbunden zu erstellen, das ein Teil des von dieser Erweiterung erzeugten Objekts ist.

In unseren früheren Beispielen hatte das resultierende Objekt ein Auto von M-x foo2 (interniert) und ein Kader von ,(make-symbol (concatenate 'string "text-" functionname)) oder defun (beide auch interniert).

In diesem letzten Beispiel hat das Objekt ein Auto von foo1 (interniert), aber ein cadr von einem nicht unterteilten Symbol (mit dem Namen, der aus dem Ausdruck foo2 resultiert).

Und schließlich, wenn Sie das Objekt drucken drucken, wird die gedruckte Darstellung dieses Symbols für nichtfunktionierte Funktionen der Name des Symbols sein, und Lesen die gedruckte Darstellung zurück durch Auswertung würde Ursache stattdessen die Funktionszelle für das kanonische -Symbol definiert werden.

1 Tatsächlich kann die Funktion defun verwendet werden, um ein Symbol zu entschlüsseln, nach dem Aufruf von concatenate für denselben Namen würde natürlich ein neues Symbol erzeugen; aber das ist nicht wichtig für diese Diskussion.

    
phils 28.01.2014 02:51
quelle
3

FWIW, wenn Sie lexical-binding verwenden, müssen Sie kein Makro verwenden:

%Vor%     
Stefan 28.01.2014 00:00
quelle
1

Es ist Jahre her, aber ich denke, dass Sie wahrscheinlich eine fset fehlt, um die Funktion zu definieren; siehe die Dokumente , wenn Sie es wünschen eine Kompilierzeit auch.

    
MarkusQ 19.03.2009 00:18
quelle

Tags und Links