Wie ändert man den Wert eines Arguments (z. B. Nr. 1), sodass jeder Verweis darauf (das Argument Nr. 1) auf den neuen Wert erweitert wird?

Wie ändert man den Wert eines Arguments (z. B. Nr. 1), sodass jeder Verweis darauf (das Argument Nr. 1) auf den neuen Wert erweitert wird?

Ich habe mich gefragt, wie ich basierend auf seinem Wert in etwas anderes ändern kann #1, sodass alles, #1was auf die Änderung folgt, den geänderten Wert enthält und nicht den ursprünglichen Wert (der von außen an das Makro übergeben wurde).

\def\myT#1%
  {%
    \ifnum#1=0
      % #1=1
    \fi
    #1
  }
\myT{0} % 1
\myT{1} % 1
\myT[2} % 2

BEARBEITEN (Workaround; würde lieber #1den Wert von direkt ändern, wie #1=1, als ein verschachteltes \myTmit Argument von zu erweitern 1, wie unten):

\def\myT#1%
  {%
    \ifnum#1=0
      \myT{1}%
    \else
      #1%
    \fi
  }
\myT{0} % 1
\myT{1} % 1
\myT{2} % 2

Antwort1

#1Sie können Werte nur mithilfe des entsprechenden Arguments „zuweisen“ .

Die Art der Aufgabe, die Sie darstellen, lässt sich bequemer mit zwei Makros erledigen. Sie können zwar aufrufen, \myT{1}wenn das ursprüngliche Argument lautet 0, dies ist jedoch ineffizient, da dadurch eine bereits durchgeführte Prüfung erneut ausgeführt wird.

\def\myT#1{%
  \ifnum#1=0
    \myTaux{1}%
  \else
    \myTaux{#1}%
  \fi
}
\def\myTaux#1{-#1-\par}

\myT{0} % 1
\myT{1} % 1
\myT{2} % 2

\bye

Es ist nichts Schlechtes daran, die Ausführung einer gewünschten Funktion auf zwei oder mehr Makros aufzuteilen. Im Gegenteil, es ist im Allgemeinen eine gute Vorgehensweise.

Antwort2

Bedenken Sie, dass Tex eine Makroverarbeitungssprache und keine funktionale Sprache ist. #1ist kein Bezeichner, der auf eine Variable verweist, die per Referenz an eine Funktion übergeben wird, sondern lediglich ein Platzhalter, in den die bereitgestellten Token eingefügt werden.

Ob es sinnvoll ist, etwas zuzuweisen, #1hängt also davon ab, was es #1ist.

gegeben

\def\myT#1%
  {%
    \ifnum#1=0
       #1=1 %HERE
    \fi
    #1 %THERE
  }
\myT{0} % 1

Die Zeile mit der Markierung HIER ist 0=1also keine Zuweisung, sondern setzt einfach 0=1. Wenn Sie jedoch dieselbe Definition verwenden, sie aber als

\newcount\zzz
\zzz=0
\myT{\zzz}

Dann wäre die Zeile mit der Markierung HIER \zzz=1und wäre eine Zuweisung, aber die Zeile mit der Markierung DORT wäre \zzzso würde nicht gesetzt werden 1müssen, \the#1was als ausgewertet würde\the\zzz

Antwort3

Der Vorgang, der dem, was Sie als „Ändern des Werts eines Arguments“ beschreiben, am nächsten kommt, besteht darin, dass das betreffende Makro sich selbst erneut aufruft und dabei das betreffende Argument geändert wird.

Diese Programmiertechnik, bei der eine Routine abhängig von bestimmten Bedingungen als letztes beendet wird und sich selbst erneut aufruft, wird Endrekursion genannt.

In der (La)TeX-Terminologie: Ein (La)TeX-Makro ist Endrekursiv, wenn, abhängig von einer bestimmten Bedingung, die letzten Token, die als Ergebnis seiner Erweiterung geliefert wurden, aus einem weiteren Aufruf stammen.

Wenn Sie \if.. \else.. \fi-Switches benötigen, um die Bedingungen für die Beendigung der Endrekursion zu prüfen, stellen Sie sicher, dass Token, die passende \else- und \fi-Zweige bilden, verarbeitet/aus dem Eingabepuffer gelöscht werden, bevor das betreffende Makro erneut aufgerufen wird. Andernfalls ist das betreffende Makro nicht endrekursiv, da die Token, die diese Zweige bilden, im Token-Stream/im Eingabepuffer verbleiben und sich dort ansammeln, bis sie zu einem Zeitpunkt verarbeitet werden, an dem die Rekursion bereits beendet ist, was zu einer unnötigen Belastung des semantischen Nests und auch zu einer unnötigen Ansammlung von Token im Eingabepuffer führt.

Sie können beispielsweise Folgendes tun:

\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\myT#1{%
  \ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
   {\myT{1}}{#1}%
}%
\myT{0}% 1

\myT{1}% 1

\myT{2}% 2
%...
\bye

Falls Sie komplexere Änderungen vornehmen müssen, kann es sinnvoll sein, Argumente nach dem Auslösen der erforderlichen Erweiterungsschritte auszutauschen. Nehmen wir ein Makro an, das zwei Argumente verarbeitet und bei dem das erste Argument den Wert 0 hat, dieses Argument durch eines mit dem Wert 1 ersetzt werden muss und das zweite Argument durch eines, bei dem der Wert um 1 erhöht ist:

% this example requires eTeX-extensions (\numexpr):
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\long\def\passfirsttosecond#1#2{#2{#1}}%
\def\myT#1#2{%
  \ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
  {%
    \expandafter\passfirsttosecond\expandafter{\number\numexpr#2+1\relax}{\myT{1}}%
  }{%
    Value of 1st arg: #1.\hfil\break
    Value of 2nd arg: #2.%
  }%
}%
\myT{0}{5}% Value of 1st arg: 1.\hfil\break Value of 2nd arg: 6.

\myT{1}{6}% Value of 1st arg: 1.\hfil\break Value of 2nd arg: 6.

\myT{2}{7}% Value of 1st arg: 2.\hfil\break Value of 2nd arg: 7.
%...
\bye

Falls mehr als zwei Argumente geändert werden müssen, können Sie Aufrufe \passfirsttosecondinnerhalb des zweiten Arguments verschachteln. Wenn Sie dies tun, erhalten Sie ein Muster, bei dem Änderungen des vorletzten k-ten Makroarguments, das geändert werden muss, direkt vor der Ausführung der vorletzten k-ten -Anweisung \passfirsttoseconddurchgeführt werden :\passfirsttosecond

Nehmen wir ein Makro an, das neun Argumente verarbeitet. Wenn das erste Argument den Wert 0 hat, muss dieses Argument durch eines mit dem Wert 1 ersetzt werden. Die folgenden Argumente müssen jeweils durch eines ersetzt werden, bei dem der Wert um 1 erhöht ist:

% this example requires eTeX-extensions (\numexpr):
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\long\def\passfirsttosecond#1#2{#2{#1}}%
\def\myT#1#2#3#4#5#6#7#8#9{%
  \ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
  {%
    \expandafter\passfirsttosecond\expandafter{\number\numexpr#9+1\relax}{%
      \expandafter\passfirsttosecond\expandafter{\number\numexpr#8+1\relax}{%
        \expandafter\passfirsttosecond\expandafter{\number\numexpr#7+1\relax}{%
          \expandafter\passfirsttosecond\expandafter{\number\numexpr#6+1\relax}{%
            \expandafter\passfirsttosecond\expandafter{\number\numexpr#5+1\relax}{%
              \expandafter\passfirsttosecond\expandafter{\number\numexpr#4+1\relax}{%
                \expandafter\passfirsttosecond\expandafter{\number\numexpr#3+1\relax}{%
                  \expandafter\passfirsttosecond\expandafter{\number\numexpr#2+1\relax}{%
                    \expandafter\passfirsttosecond\expandafter{\number\numexpr#1+1\relax}{%
                      \myT
                    }%
                  }%
                }%
              }%
            }%
          }%
        }%
      }%
    }%
  }{%
    Value of 1st arg: #1.\hfil\break
    Value of 2nd arg: #2.\hfil\break
    Value of 3rd arg: #3.\hfil\break
    Value of 4th arg: #4.\hfil\break
    Value of 5th arg: #5.\hfil\break
    Value of 6th arg: #6.\hfil\break
    Value of 7th arg: #7.\hfil\break
    Value of 8th arg: #8.\hfil\break
    Value of 9th arg: #9.%
 }%
}%
\myT{0}{4}{9}{14}{19}{24}{29}{34}{39}%
%    Value of 1st arg: 1.\hfil\break
%    Value of 2nd arg: 5.\hfil\break
%    Value of 3rd arg: 10.\hfil\break
%    Value of 4th arg: 15.\hfil\break
%    Value of 5th arg: 20.\hfil\break
%    Value of 6th arg: 25.\hfil\break
%    Value of 7th arg: 30.\hfil\break
%    Value of 8th arg: 35.\hfil\break
%    Value of 9th arg: 40.%

\myT{1}{5}{10}{15}{20}{25}{30}{35}{40}%
%    Value of 1st arg: 1.\hfil\break
%    Value of 2nd arg: 5.\hfil\break
%    Value of 3rd arg: 10.\hfil\break
%    Value of 4th arg: 15.\hfil\break
%    Value of 5th arg: 20.\hfil\break
%    Value of 6th arg: 25.\hfil\break
%    Value of 7th arg: 30.\hfil\break
%    Value of 8th arg: 35.\hfil\break
%    Value of 9th arg: 40.%

\myT{2}{1}{2}{3}{4}{5}{6}{7}{8}%
%    Value of 1st arg: 2.\hfil\break
%    Value of 2nd arg: 1.\hfil\break
%    Value of 3rd arg: 2.\hfil\break
%    Value of 4th arg: 3.\hfil\break
%    Value of 5th arg: 4.\hfil\break
%    Value of 6th arg: 5.\hfil\break
%    Value of 7th arg: 6.\hfil\break
%    Value of 8th arg: 7.\hfil\break
%    Value of 9th arg: 8.%
%...
\bye

Wie Sie den obigen Beispielen entnehmen können, geht es bei der (La)TeX-Programmierung und insbesondere beim (La)TeX-Konzept der „Erweiterung“ weniger um die Zuweisung von Werten zu Variablen, sondern vielmehr um das Aufwirbeln sogenannter Token, wobei Sie Token für Dinge/Elemente nehmen können, die im Token-Stream/Eingabestream hintereinander platziert werden.

Die folgende Analogie kann hilfreich sein, wenn man sich mit dem Konzept der Makro-Erweiterung in (La)TeX vertraut machen möchte:

Wenn (La)TeX eine .tex-Eingabedatei verarbeitet, also einen Teil des (La)TeX-Quellcodes, verwendet es im ersten Schritt diese .tex-Eingabedatei für eine Reihe von Anweisungen zum Einfügen von Token in den Token-Stream. (Diese Token können Zeichen-Token beliebiger Kategorie, Steuerwort-Token und Steuersymbol-Token sein.) In späteren Schritten werden diese Token verarbeitet. Während der Erweiterungsphase werden Token entfernt/durch andere Token ersetzt. Während der Erweiterungsphase kann auch die Reihenfolge geändert werden, in der Token im Token-Stream erscheinen.

Falls Sie an Details zu den Regeln interessiert sind, die (La)TeX beim Einfügen von Token in den Token-Stream beim Lesen der .tex-Eingabedatei befolgt, finden Sie in der Diskussion"Quellcode-Einrückung"könnte für Sie von Interesse sein.

Falls Sie sich dafür interessieren, welche Arten von Token es in (La)TeX gibt, finden Sie die Diskussion„Was ist der Unterschied zwischen ‚Makro‘ und ‚Befehl‘?“könnte für Sie von Interesse sein.

Falls Sie daran interessiert sind, wie Makroargumente in (La)TeX behandelt werden, finden Sie die Diskussion„Wie sucht TeX nach abgegrenzten Argumenten?“könnte für Sie von Interesse sein.

Falls Sie sich für Expansionstricks interessieren, die Diskussion„Wie kann ich die Anzahl der Expandafters beim Anhängen an ein CSNAME-Makro ermitteln?“könnte für Sie von Interesse sein.


Wie siracusa bereits anmerkte, können Sie einem Makroargument keine andere Tokensequenz zuweisen, wenn (La)TeX dieses Argument aus dem Tokenstream gesammelt hat.
Sie können (La)TeX jedoch dieses Argument untersuchen lassen, um „zu entscheiden“, welche Token am Ende übergeben werden sollen. Dies kann direkt oder durch Aufruf eines anderen Makros erfolgen, bei dem die übergebenen Argumente vom Ergebnis der Untersuchung abhängen.

Beispiel für Direktansprache:

\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\myT#1{%
  \ifnum#1=0 %<- The space before the percent terminates \ifnum's second number, i.e., the number 0. It gets discarded silently.
    \expandafter\firstoftwo%<-\expandafter removes the tokens that form the else-branch and the \fi
  \else
    \expandafter\secondoftwo%<-\expandafter removes the \fi
  \fi
  {1}{#1}%
}%
\myT{0} % 1
\myT{1} % 1
\myT[2} % 2

Wird normalerweise \romannumeralverwendet, um Token zu erhalten, die die römische Notation einer Ganzzahl in Kleinbuchstaben bilden. Wenn \romannumeraleine Zahl gesucht werden muss, erweitert (La)TeX weiterhin erweiterbare Token, bis entweder eine Zahl gefunden wird oder eine Fehlermeldung ausgegeben wird. Falls die fragliche Zahl nicht positiv ist, wird (La)TeX sie stillschweigend schlucken, ohne ein Token zu liefern. Daher können Sie (ab)verwenden, \romannumeralum eine Menge Erweiterungsarbeit und Argumentprüfungsarbeit auszulösen, solange Sie sicherstellen, dass (La)TeX am Ende eine Zahl findet, die nicht positiv ist.

Ein weiteres Beispiel für eine direkte Vorgehensweise, bei der man es \romannumeralals Auslöser für die Erweiterung aufruft, sodass sichergestellt ist, dass das Ergebnis \myTin jedem Fall nach zwei Erweiterungsschritten bzw. nach zweimaligem "Treffen" der Fundstelle \myTvon geliefert wird:\expandafter

\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\myT#1{%
   \romannunmeral0%<-While searching the number for \romannumneral, (La)TeX finds the digit-token 0 and keeps
                  %   triggering expansion while searching in the token-stream for
                  %   more digit-tokens or something that terminates the number.
   \ifnum#1=0 %<- The space before the percent terminates \ifnum's second number, i.e., the number 0. It gets discarded silently.
     \expandafter\firstoftwo%<-\expandafter removes the tokens that form the else-branch and the \fi
   \else
     \expandafter\secondoftwo%<-\expandafter removes the \fi
   \fi
   { 1}{ #1}% <- The space that precedes `1`/`#1` will be right
            %    behind the "0" from "\romannumeral0".
            %    Therefore it stops (La)TeX's seeking for digits for
            %    \rommanumeral which means that after doing
            %    expansion-work/argument-examining-work (La)TeX
            %    does only find the non-positive number "0" and 
            %    thus the result/effect of `\romannumeral` is:
            %    "Triggering doing a lot of expansion- and argument-
            %     examining-work while silently discarding the
            %     digit-token 0 which forms a non-positive number
            %     and the space behind it and not delivering
            %     anything in roman-notation at all."
}%
\myT{0} % 1
\myT{1} % 1
\myT[2} % 2

Beispiel mit Aufruf eines weiteren Makros:

\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\newcommand\myinnerT[1]{%
  Here \firstoftwo{\LaTeX}{} can do to the argument, #1, whatever shall be done.%
}%
\def\myT#1{%
  % Here the argument is examined for deciding how to call \myinnerT:
  \ifnum#1=0 %
    \expandafter\firstoftwo
  \else
    \expandafter\secondoftwo
  \fi
  {\myinnerT{1}}{\myinnerT{#1}}%
}%
\myT{0} % 1
\myT{1} % 1
\myT[2} % 2

Beachten Sie, dass in den obigen Beispielen keine Überprüfung durchgeführt wird, ob das Argument bei einer bestimmten Expansionsstufe überhaupt eine Zahl ergibt. (Streng genommen ist eine solche Überprüfung unmöglich, wenn das Argument aus beliebigen Token-Sequenzen bestehen kann, da in diesem Fall die Token, die das Argument bilden, selbst die (La)TeX-Implementierung eines beliebigen Algorithmus bilden könnten und daher eine solche Überprüfung (unter anderem) die Lösung desHalteproblem.)

verwandte Informationen