
Ich habe vor kurzem eine Frage zum Schreiben eines Makros in reinem TeX gepostet, das die Elemente in einer benutzerdefinierten Liste ändern würde. Ich erwähnte beiläufig meine Abneigung gegen die TeX-Oberfläche, woraufhin mich jemand auf LaTeX3 aufmerksam machte, das, wie das Handbuch verspricht, eher einer modernen Programmiersprache ähneln soll. Ich fange gerade erst mit dem Programmieren in TeX an, daher war es ein harter Kampf, das Handbuch zu verstehen. Ich nehme an, das liegt daran, dass das Handbuch für erfahrene TeX-Benutzer geschrieben wurde; es scheint jedoch keine Alternative für Leute zu geben, die gerade erst mit LaTeX3/TeX anfangen, also bleibt mir nichts anderes übrig, als mit dem zu arbeiten, was ich habe. Aus diesem Grund poste ich dies. Das Handbuch ist verwirrend, und ich möchte etwas von dieser Verwirrung aufklären, indem ich Ihnen einige einfache Fragen zur Syntax stelle.
Ich sollte erwähnen, dass die Person, die mir von LaTeX3 erzählt hat, mir auch eine Lösung für meinen ursprünglichen Beitrag mithilfe der LaTeX3-Schnittstelle gegeben hat. Ich konnte diese Lösung in Verbindung mit dem Handbuch verwenden, um einige grundlegende Fakten zur LaTeX3-Syntax herauszufinden. Ich werde darüber sprechen, was ich herausgefunden habe, aber seien Sie gewarnt: Einiges davon basiert auf meinen eigenen Schlussfolgerungen – die ich mithilfe des vom Stackexchange-Benutzer bereitgestellten Beispiels gezogen habe – und nicht auf expliziten Anweisungen im Handbuch. Erwarten Sie also Fehler. Ich möchte, dass Sie wissen, dass ich die Dinge nicht verschleiere, wenn ich manchmal meine eigene Terminologie verwende. Es ist einfach schwierig, strukturiert über ein Thema zu sprechen, das Sie nicht vollständig verstehen.
Außerdem schreibe ich dies aufgrund der Länge als separaten Beitrag und nicht als Kommentar. Vielen Dank im Voraus.
----------------------------------------------------------------------------------------------------------------------------------
Funktionsdefinitionen.
Was ich bisher herausgefunden habe:
Eine neue Funktion wird unter anderem mit folgendem Code definiert:
\cs_new_<restrictions>:Npn <function name> <function parameters> {<replacement code>}
Dies \cs_new_<restrictions>
ist ein LaTeX-Befehl, der Npn dient dazu, dem „Parser“ der Schnittstelle mitzuteilen, was er nach diesem \cs_new_<restrictions>: Npn
Codeteil erwarten soll, in diesem Fall ein einzelnes Token-Steuerwort, d. h <function name>
. ein oder mehrere Parameter, d. h. <function parameters>
, und eine Token-Liste, d. h. {<code>}
, die die Funktion ersetzt.
Wenn ich also eine neue Funktion definieren möchte, die beispielsweise 4 Argumente annimmt, könnte ich mit dem folgenden Code vorgehen
\cs_new_<restrictions>:Npn \myfunction #1 #2 #3 #4 {<code>}
Und ähnlich könnte der Code für eine Funktion mit 2 Argumenten etwa so aussehen
\cs_new_<restrictions>:Npn \myfunction #1 #2 {<code>}
Natürlich gehe ich davon aus - und korrigieren Sie mich, wenn ich falsch liege - dass die Leerzeichen nicht notwendig sind, da dem Parser bereits mitgeteilt wurde, wie er die "Meta"-Argumente ( <function name>
, <parameters>
, {<code>}
) mithilfe der "Meta-Signatur" voneinander abgrenzen kann.Npn.
Wenn ich nun die #'s loswerden möchte, kann ich den folgenden allgemeinen Befehl verwenden
\cs_new_<restrictions>:Nn <function name>:<function signature> {<code>}
Ähnliches, außer dass der Parser jetzt <function signature>
nach ein Nn, NnN, TnN oder etwas anderes erwartet <function name>
.
Eine Funktion mit 4 Argumenten könnte also wie folgt aussehen
\cs_new_<restrictions>:Nn \myfunction:NNNN {<code>}
und eines mit 2 Argumenten wie diesem
\cs_new_<restrictions>:Nn \myfunction:NN {<code>}
Es gibt weitere Befehle iml3grundlagenBibliothek zum Erstellen von Funktionen, aber ihre allgemeine Struktur scheint im Wesentlichen dieselbe zu sein. Der einzige Unterschied liegt in ihrer Funktionalität. Wenn Sie beispielsweise \cs_set...
anstelle von verwenden \cs_new...
, wird die Funktion lokal statt global. Ich werde wahrscheinlich einen Folgebeitrag schreiben und um weitere Einzelheiten zu bitten, was E-Type- und X-Type-Erweiterungen sind, aber für den Moment denke ich, dass es am besten ist, sich auf das Gesamtbild zu beschränken.
Ist das jedenfalls soweit richtig?
Okay, weiter geht‘s.
Variablendefinitionen.
Was ich bisher herausgefunden habe:
Es gibt eine ganze Reihe von Datentypen in LaTeX3, aber die wichtigsten sindToken-Listen,Saiten,Ganzzahlen,Sequenzen, UndKomma-getrennte ListenSie verwenden jeweils ihre eigenen Abkürzungen, aber im Allgemeinen deklarieren Sie beim Definieren einer neuen Variable den Typ und geben anschließend ein Schlüsselwort wieneuoderKonstanteabhängig davon, ob Sie die Variable initialisieren.
Wenn ich beispielsweise eineTokenlisteVariable, ich verwende den Code:
\tl_new:N \mytokenList
und dann kann ich irgendwo später eine Tokenliste \mytokenList
mit dem Code speichern:
\tl_set:Nn \mytokenList {<tokens>}
Wenn ich aber von Anfang an weiß, welche Daten ich in der Variable speichern möchte, kann ich stattdessen diesen Befehl verwenden (gilt nicht fürSequenzenoderGanzzahlen)
\tl_const:Nn \mytokenList {<tokens>}
Abgesehen davon: Mir ist aufgefallen, dass sogar Variablen „Funktionssignaturen“ haben. Das macht es wahrscheinlich einfacher, ein Analyseregime zu definieren.
Das ist so allgemein, wie ich nur sein kann, bevor ich angeben muss, auf welchen Datentyp ich mich beziehe, da jedem seine eigenen zugehörigen Operationen zugeordnet sind.
----------------------------------------------------------------------------------------------------------------------------------
Das ist alles, was ich bisher habe. Ich würde mich über Feedback freuen. So etwas lernt man nicht so leicht alleine! Vor allem nicht mit minimalen TeX-Kenntnissen. Ich entschuldige mich also, wenn sich einige von Ihnen das ansehen und denken: „Na ja, das ist doch klar.“ Trotzdem, danke nochmal.
Antwort1
Es gibt zwei Hauptmethoden zum Definieren von Funktionen:
\cs_new<restrictions>:Npn
\cs_new<restrictions>:Nn
wo oder sein kann _protected
._nopar
_protected_nopar
Beide Methoden prüfen, ob das N
folgende -Argument (also ein einzelnes Token) eine Steuersequenz (oder ein aktives Zeichen) ist, die derzeit nicht definiert ist undglobalDefinieren Sie die Steuersequenz.
Was ist der Unterschied? Dass die erste Familie nach der zu definierenden Steuersequenz einen „Parametertext“ verlangt, bevor {
der „Ersetzungstext“ der Funktion abgegrenzt wird.
Der „Parametertext“ kann eine beliebige Token-Folge sein #1
, einschließlich #2
usw. bis #9
. Um jedoch die volle Leistungsfähigkeit dieser Freiheit zu nutzen, müssen Sie mit Kapitel 20 des TeXbook und dem Konzept des „begrenzten Arguments“ vertraut sein.
Aber lassen Sie es uns einfach halten. Die beiden folgenden Codeteile sind völlig gleichwertig:
\cs_new:Npn \harry_foo:nn #1 #2 { -#1-#2- }
\cs_new:Nn \harry_foo:nn { -#1-#2- }
weil dieser den Parametertext automatisch #1#2
anhand der Signatur der zu definierenden Funktion liefert, in diesem Fall :nn
.
Die Signatur sollte aus einer (möglicherweise leeren) Folge von n
und N
Zeichen bestehen.
Beachten Sie, dass Leerzeichen ignoriert werden, wenn \ExplSyntaxOn
aktiv ist.
\cs_new:Npn \harry_foo:nn #1 #2 { -#1-#2- }
\cs_new:Npn \harry_foo:nn #1#2 { -#1-#2- }
\cs_new:Npn \harry_foo:nn #1#2{ -#1-#2- }
sind alle gleichwertig. Auch nach könnte ein Leerzeichen stehen #
, aber das würde ich nicht empfehlen.
Die Syntaxregeln von TeX legen fest, dass bei der Erwartung eines „Parametertextes“ (also bei der Ausführung von \def
oder ähnlichen Zuweisungen und nach dem Speichern des Namens des zu definierenden Makros)allesbis zum ersten {
ist Teil des Parametertextes. Es gibt keine Möglichkeit, den Parametertext vorherzusehen, daher der spezielle p
Argumentspezifizierer, der einfach „alles bis {
“ bedeutet.
Nur einfache Parametertexte wie #1
usw. #1#2
können automatisch generiert werden, was geschieht, wenn man die zweite Familie verwendet \cs_new<restrictions>:Nn
.
Wo liegst du falsch? Ich gehe davon aus, dass du es T
als Spezifizierer in der Signatur verwenden kannst. Die Argumentspezifizierer T
oder F
werden hinzugefügt, wenn \prg_new_conditional<restrictions>:Nnn
ausgeführt wird.
Auch Ihre Analyse des Parametertextes ist, wie zuvor gezeigt, falsch.
Was ist mit \cs_set<restrictions>:Npn
und :Nn
? Es gilt alles wie oben, mit dem Unterschied, dass die zu definierende Funktion nicht auf ihre Definition überprüft wird und ihre Bedeutung stillschweigend überschrieben wird, der Gültigkeitsbereich der Deklaration jedoch mit der aktuellen Gruppe übereinstimmt. Normalerweise \cs_set...
wird für temporäre Funktionen verwendet, die sich an den Kontext anpassen müssen, sodass ihre Bedeutung nicht festgelegt ist.
Die Namenskonventionen für Variablenempfiehltdass ihr Name mit oder beginnt l
. g
Eigentlich sollten c
im Code verwendete Variablen expl3
der Konvention entsprechen; es ist möglich, „normale“ Namen zu verwenden, wie z. B. \myTokenList
für Variablen vom Typ tl
(eventuell auch clist
), die im Dokument verwendet werden sollen.
Auf Variablen, die mit beginnen, l
sollte immer lokal eingewirkt werden ( \tl_set:Nn
z. B. ), während auf Variablen, die mit beginnen, g
immer global eingewirkt werden sollte ( \tl_gset:Nn
z. B. ).
Variablen, die mit beginnen, c
sindKonstantenund sollteniemalsnach Zuweisung eines Wertes wird darauf reagiert, aber nur verwendet.
Man kann Konstanten definieren mit
\tl_const:Nn \c_harry_foo_tl {<tokens>}
\str_const:Nn \c_harry_foo_str {<tokens>}
\clist_const:Nn \c_harry_foo_clist {<comma list>}
\seq_const_from_clist:Nn \c_harry_foo_seq {<comma list>}
\prop_const_from_keyval:Nn \c_harry_foo_prop {<key-value list>}
\int_const:Nn \c_harry_foo_int {<integer expression>}
\fp_const:Nn \c_harry_foo_int {<fp expression>}
\bool_const:Nn \c_harry_foo_bool {<boolean expression>}
\dim_const:Nn \c_harry_foo_dim {<dimen expression>}
\skip_const:Nn \c_harry_foo_dim {<skip expression>}
\muskip_const:Nn \c_harry_foo_dim {<muskip expression>}
\intarray_const_from_clist:Nn \c_harry_foo_intarray {<comma list>}
\regex_const:Nn \c_harry_foo_regex {<regex>}
\cc_tab_const:Nn \c_harry_foo_cctab {<code>}