Ich sehe viele Makros, bei denen es sich um bedingte Tests handelt, gefolgt von einem {true}{false}
Paar, das so definiert ist, dass es zu folgendem Ergebnis führt:
\expandafter\@firstoftwo
oder
\expandafter\@secondoftwo
Warum sind diese \expandafter
S da? Ich hätte gedacht, sie würden nur die erste Klammer im folgenden {true}{false}
Paar fangen?
Antwort1
Die \expandafter
s sollen sich mit dem Folgenden \else
oder befassen \fi
. Wie in der Frage, auf die Ryan verweist, sieht der vollständige Code etwa so aus:
\def\ifeq#1#2{%
\ifx#1#2\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
Lassen Sie uns verfolgen, was passiert. Wir setzen \ifeq\stuff\nonsense{true}{false}
in unser Dokument. Das \ifeq
absorbiert das \stuff
und \nonsense
so haben wir nach der ersten Erweiterung:
\ifx\stuff\nonsense\relax
\expandafter\@firstofone
\else
\expandafter\@secondoftwo
\fi
{true}{false}
Nehmen wir an, dass dies der \stuff
Fall ist \nonsense
(das heißt, dass die Bedingung wahr ist). Dann \ifx
beginnt der, alles in seinem „wahren“ Pfad zu erweitern, der als alles bis zum nächsten \else
oder \fi
(Modulo-Verschachtelung) definiert ist. Der entscheidende Punkt ist, dass er beginnt,Ersteund sucht nicht nach dem \else
oder \fi
. TeX geht davon aus, dass es das wissen wird, wenn es dort ankommt. Also haben wir:
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{true}{false}
TeX erweitert das jetzt \expandafter
. Dies hat zur Folge, dass über das \@firstoftwo
bis zum gereicht wird \else
und das erweitert wird. Das „Erweitern“ des \else
bedeutet, es und alles bis zum entsprechenden \fi
aus dem Stream zu entfernen. Es bleibt also übrig:
\@firstoftwo{true}{false}
Und dann wird dies zum einfachen erweitert true
.
Ohne das \expandafter
„s“ erhalten wir:
\@firstoftwo
\else
\@secondoftwo
\fi
{true}{false}
TeX erweitert immer noch den wahren Zweig und erweitert daher \@firstoftwo
. Dies absorbiert zwei Token/geschweifte Gruppen aus dem Stream. Dies sind zufällig \else
und \@secondoftwo
. Es lässt dann das erste im Stream, sodass wir erhalten
\else
\fi
{true}{false}
Das \else
entspricht der Bedingung, sodass TeX dies und alles bis zum \fi
Verlassen {true}{false}
im Stream absorbiert. Was nicht das ist, was wir wollten.
Zusammenfassend lässt sich sagen,\expandafters
gilt es, die bedingte Verarbeitung aus dem Weg zu räumen, bevor dieErgebnisder Bedingung wird erweitert, wodurch sichergestellt wird, dass das Ergebnis der Bedingung die nächsten Bits im Datenstrom sieht und nicht die Bits, die von der unvollendeten Bedingung übrig geblieben sind.
Antwort2
Ich würde das von einem anderen Standpunkt aus angehen. Primitive Konditionale in TeX testen auf eine Bedingung, die Token aus dem Eingabestrom aufnehmen kann oder nicht, bis die Wahrheit oder Falschheit der Bedingung festgestellt werden kann. Bezeichnen wir also durch das primitive Konditional zusammen mit der (möglicherweise leeren) Liste der Token , <IF>
die aufgenommen werden müssen. Zum Beispiel \ifhmode
benötigt kein Token, \ifx
benötigt zwei. In einigen Fällen ( \if
,,,,, ) führt TeX Erweiterungen durch , um die erforderliche Art von Token für den Test zu finden; in anderen ( ,,,,,,,,, ) wird keine Erweiterung durchgeführt. So werden das Konditional und die erforderlichen Token bezeichnet\ifcat
\ifnum
\ifdim
\ifx
\ifmmode
\ifhmode
\ifvmode
\ifinner
\iftrue
\iffalse
<IF>
nachDer Ausbau ist erfolgt und der Zustand kann geprüft werden.
Die typische Konstruktion, auf die Sie sich beziehen, ist
<IF>
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
wo wir bereits
\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}
Allgemeiner gesagt haben wir
<IF><true>\else<false>\fi
oder
\IF<true>\fi
wobei sowohl <true>
als auch <false>
leer sein können.
Die Bedingung ist wahr
TeX entfernt es einfach <IF>
aus dem Eingabestrom und hinterlässt entweder
<true>\else<false>\fi
oder
<true>\fi
Die Bedingung ist falsch
TeX sucht nach dem nächsten \else
Token und berücksichtigt dabei verschachtelte Bedingungen, die in vorkommen könnten, <true>
ohne etwas zu erweitern. Daher wird eine \else
Zugehörigkeit zu einer verschachtelten Bedingung \if...\else\fi
innerhalb übersprungen. Die Erweiterung ist auch in diesem Fall leer und alle Token bis zu verschwinden. Falls keine Übereinstimmung gefunden wird, hört TeX auf, nach der Übereinstimmung zu suchen , die besser irgendwo sein sollte. In beiden Fällen würden wir also entweder<true>
\else
\else
\fi
<false>\fi
oder einfach nichts, wenn kein \else
Zweig da war.
Dies wird durch die folgende TeX-Eingabe bewiesen:
\def\showx{\show\x}
\def\showif{\afterassignment\showx
\expandafter\def\expandafter\x\expandafter}
\showif{\ifvmode<true>\else<false>\fi}
\showif{\ifvmode<true>\fi}
\showif{\ifhmode<true>\else<false>\fi}
\showif{\ifhmode<true>\fi}
\bye
Wenn Sie TeX darauf ausführen, wird das folgende Transkript erstellt:
This is TeX, Version 3.1415926 (TeX Live 2012)
(./plkfi.tex
> \x=macro:
-><true>\else <false>\fi .
\showx ->\show \x
l.5 \showif{\ifvmode<true>\else<false>\fi}
?
> \x=macro:
-><true>\fi .
\showx ->\show \x
l.6 \showif{\ifvmode<true>\fi}
?
> \x=macro:
-><false>\fi .
\showx ->\show \x
l.7 \showif{\ifhmode<true>\else<false>\fi}
?
> \x=macro:
->.
\showx ->\show \x
l.8 \showif{\ifhmode<true>\fi}
?
Was passiert als nächstes
Die Erweiterung von
\else
besteht darin, alles bis auf das passende Element zu entfernen.\fi
und nichts im Eingabestrom zu belassen.Verschachtelte Bedingungen werden wie bisher berücksichtigt.Die Erweiterung von
\fi
ist leer.
Die Rolle von\expandafter
Jetzt haben wir die Grundlagen, auf die wir uns stürzen können \expandafter
.
Sehen wir uns eine typische Verwendung an:
\def\@ifundefined#1{%
\expandafter\ifx\csname#1\endcsname\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi}
Wir möchten sagen können
\@ifundefined{foo}{T}{F}
Daher wird das mit dem Argument als Namen erstellte Makro verglichen \relax
(das ist der wirklich uninteressante Teil) und dann wird dem True- oder False-Zweig gefolgt.
Nach der Entfernung der <IF>
verbleiben wir bei
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi{T}{F}
und jetzt erweitert TeX ordnungsgemäß das erste Token. Dies löst die Erweiterung aus \else
und hier beginnt der Spaß.
Der Ausbau von\expandafter
besteht darin, das übernächste Token (sofern möglich) zu erweitern und verschwinden zu lassen.Somit \else
wird gemäß der obigen Regel erweitert und wir erhalten
\@firstoftwo{T}{F}
Dies führt dazu, dass T
der Eingabestrom verlassen wird.
Nehmen wir nun an, dass die Bedingung falsch ist. Dann <IF>
wird zusammen mit allem bis entfernt \else
, übrig bleibt
\expandafter\@secondoftwo\fi{T}{F}
Jetzt \expandafter
tut es seine Aufgabe, sich auszudehnen \fi
und zu verschwinden. Somit erhalten wir
\@secondoftwo{T}{F}
das geht endlich F
.
Wichtiger Hinweis
Im Falle von \@ifundefined{foo}{T}{F}
sind wir in der Lage, zu bekommen T
oder F
ohne jemalsAusführenein Befehl: Es wurde nur die Makroerweiterung verwendet. Dies macht \@ifundefined
ein ähnlich definiertes Makro nutzbar in \edef
:
\edef\test{\@ifundefined{foo}{T}{F}}
wird gleichbedeutend sein mit
\def\test{T}
falls \foo
definiert ist (und nicht äquivalent zu \relax
, wie in LaTeX üblich) oder zu
\def\test{F}
wenn \foo
nicht definiert ist (oder gleichwertig mit \relax
).
Was würde ohne passieren \expandafter
? Mit einem echten Konditional stünde TeX vor
\@firstoftwo\else\@secondoftwo\fi{T}{F}
und die beiden Argumente für \@firstoftwo
wären \else
und \@secondoftwo
, die aber nichts Sinnvolles bewirken würden, oder?
In ähnlicher Weise würden wir für eine falsche Bedingung erhalten
\@secondoftwo\fi{T}{F}
und wieder würden die Dinge schief gehen.
Antwort3
Der vollständige Kontext für solchen Code befindet sich in bedingten Makros wie
\def\IfZero#1{%
\ifnum0=#1\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
Die \expandafter
s sind notwendig, wenn Sie den Code in der weniger formatierten Weise betrachten:
\def\IfZero#1{\ifnum0=#1\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}
(Entschuldigung für die lange Zeile), in der kein Hinweis auf die Struktur der TeX-Bedingungsblöcke gegeben wird. Wie Sie sehen, \@firstoftwo
ist das Token „nach“ \else
und das nach \@secondoftwo
ist \fi
, die jeweils durch erweitert werden \expandafter
. Der Zweck dieser Albernheit besteht darin, dass TeX nicht die gesamte Bedingung liest, wenn es die erweitert \ifnum
; es scannt nur vorwärts zum richtigen True- oder False-Block und fährt von dort aus fort. Die \else
oder \fi
bleiben im Eingabestrom! Sobald sie erweitert sind, scannt TeX bis zum Ende der Bedingung und das nächste im Eingabestrom ist das, was auf folgt \IfZero
.
Ohne wären die durch und \expandafter
verbrauchten „zwei“ jeweils und und das folgende Makroargument, statt dem, was eigentlich beabsichtigt ist, nämlich den beiden folgenden Makroargumenten, die als das „zweite“ und „dritte“ „Argument“ von genommen werden .\@firstoftwo
\@secondoftwo
\else\@secondoftwo
\fi
\IfZero