Warum die Redewendung \expandafter\@firstoftwo?

Warum die Redewendung \expandafter\@firstoftwo?

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 \expandafterS da? Ich hätte gedacht, sie würden nur die erste Klammer im folgenden {true}{false}Paar fangen?

Antwort1

Die \expandafters sollen sich mit dem Folgenden \elseoder 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 \ifeqabsorbiert das \stuffund \nonsenseso haben wir nach der ersten Erweiterung:

\ifx\stuff\nonsense\relax
  \expandafter\@firstofone
\else
  \expandafter\@secondoftwo
\fi
{true}{false}

Nehmen wir an, dass dies der \stuffFall ist \nonsense(das heißt, dass die Bedingung wahr ist). Dann \ifxbeginnt der, alles in seinem „wahren“ Pfad zu erweitern, der als alles bis zum nächsten \elseoder \fi(Modulo-Verschachtelung) definiert ist. Der entscheidende Punkt ist, dass er beginnt,Ersteund sucht nicht nach dem \elseoder \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 \@firstoftwobis zum gereicht wird \elseund das erweitert wird. Das „Erweitern“ des \elsebedeutet, es und alles bis zum entsprechenden \fiaus 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 \elseund \@secondoftwo. Es lässt dann das erste im Stream, sodass wir erhalten

\else
\fi
{true}{false}

Das \elseentspricht der Bedingung, sodass TeX dies und alles bis zum \fiVerlassen {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 \ifhmodebenötigt kein Token, \ifxbenö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 \elseToken und berücksichtigt dabei verschachtelte Bedingungen, die in vorkommen könnten, <true>ohne etwas zu erweitern. Daher wird eine \elseZugehörigkeit zu einer verschachtelten Bedingung \if...\else\fiinnerhalb ü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 \elseZweig 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 \elsebesteht 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 \fiist 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 \elseund hier beginnt der Spaß.

Der Ausbau von\expandafter besteht darin, das übernächste Token (sofern möglich) zu erweitern und verschwinden zu lassen.Somit \elsewird gemäß der obigen Regel erweitert und wir erhalten

\@firstoftwo{T}{F}

Dies führt dazu, dass Tder 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 \expandaftertut es seine Aufgabe, sich auszudehnen \fiund 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 Toder Fohne jemalsAusführenein Befehl: Es wurde nur die Makroerweiterung verwendet. Dies macht \@ifundefinedein ähnlich definiertes Makro nutzbar in \edef:

\edef\test{\@ifundefined{foo}{T}{F}}

wird gleichbedeutend sein mit

\def\test{T}

falls \foodefiniert ist (und nicht äquivalent zu \relax, wie in LaTeX üblich) oder zu

\def\test{F}

wenn \foonicht 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 \@firstoftwowären \elseund \@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 \expandafters 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, \@firstoftwoist das Token „nach“ \elseund das nach \@secondoftwoist \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 \elseoder \fibleiben 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 \expandafterverbrauchten „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

verwandte Informationen