119

Writing (La)TeX code sometimes requires a degree of guile. Here (in no particular order) are two of my favourite examples.

Macros ending with spaces

Pete asked how to see the implementation of \LaTeX, since \show\LaTeX results in \protect \LaTeX. Joseph Wright's suggestion made my day. (I should probably try to get out more).

\let\protect\show
\LaTeX

Uppercasing a variable

I asked how to store the upper case counterpart of a string stored in a variable, because

\def\word{abc}
\def\WORD{\MakeUppercase{\word}}
\show\WORD

returns \MakeUppercase {abc}. Bruno Le Floch offered a superb solution.

\MakeUppercase{\gdef\noexpand\WORD{\word}}

What are your favourite cunning (La)TeX tricks?

Moderator note: this should probably be community wiki.

2
  • 5
    We should also warn of dangerous uses of primitives and tricks. The implications are not always clear to the neophyte (I too am a novice). I have seen a few dangerous assignments but the following is one type that worries me most: \let\num\m@ne A few commands later the programmer then did \global\advance\num2 This dangerously changes the meaning of \m@ne, as \showthe\m@ne shows. The assignment is dangerous enough without \global.
    – Ahmed Musa
    Dec 15, 2011 at 17:19
  • @AhmedMusa Good catch. However, being picky, \showthe\m@ne reveals that meanings don't change. Both the token \m@ne and the token \num serve the purpose of accessing the same count-register whose value - by convention - should always be -1. \global\advance\num2 increases the value of that count-register by 2 and thus breaks that convention and thus might break any code where it is relied on that convention. Dec 1, 2022 at 18:48

8 Answers 8

55

This is my killing two birds with one stone technique. Sorting a table and having markdown syntax without catcode changes.

First create a list and a helper macro to add elements.

\let\alist\@empty

\def\addtolist#1#2{%
  \lst@lAddTo#1{#2}}

Create two commands one to sort based on Column A, as a primary index or Column B.

\def\RA#1|#2|#3|#4;{%
  \addtolist{\alist}{#1#2,}%
  \expandafter\gdef\csname#1#2\endcsname{\textit{#1}&#2&#3&#4\cr\relax}
  \lst@BubbleSort{\alist}
}

The sorting macro is from the listings documentation class lstdoc. Data is added as shown below, using the semicolon as an end of line delimiter is a left over from my Pascal days, you can use space if your last column is just numbers or single words.

\RA Lactarius fallax      | velvety milk cap |edible |potentially risky;  
\RA Lactarius camphoratus | candy cap        |edible |aromatic qualities;

In the minimal everything is placed in a box, but it can equally work well using environments or more complicated macros. Change \RA to \RB to sort based on the second column as a primary index.

\documentclass{article}
\usepackage{lstdoc,booktabs}
\begin{document}
\makeatletter
\let\alist\@empty

\def\addtolist#1#2{%
  \lst@lAddTo#1{#2}
}

\def\RA#1|#2|#3|#4;{%
  \addtolist{\alist}{#1#2,}%
  \expandafter\gdef\csname#1#2\endcsname{\textit{#1}&#2&#3&#4\cr\relax}
  \lst@BubbleSort{\alist}
}

\def\RB#1|#2|#3|#4;{%
   \addtolist{\alist}{#2#1,}%
   \expandafter\gdef\csname#2#1\endcsname{\textit{#1}&#2&#3&#4\cr\relax}
   \lst@BubbleSort{\alist}
}

%% adding the data now
\RA Lactarius fallax      | velvety milk cap |edible |potentially risky;  
\RA Lactarius camphoratus | candy cap        |edible |aromatic qualities;
\RA Suillus pungens       | slippery Jack    |edible |poor taste;
\RA Lactarius affinis     | kindred milk     |edible |unpalatable;
\RA Calocybe carnea       | pink fairhead    |edible |potentially risky;
\RA Amateta ocreata       | death angel      |inedible |highly poisonous;   

%% typesetting the table
\newsavebox{\tempbox}
\savebox{\tempbox}{
\centering
\begin{tabular}{llll}
  \toprule[1pt]
  Species & Common name & Edibility & Remarks\\
  \midrule
  \@for\i:=\alist \do{\csname\i\endcsname}
  \vspace{-14pt}\\\bottomrule
\end{tabular}
}

\begin{table}
\usebox{\tempbox}
\caption{Some mushrooms from Wikipedia}
\end{table}
\end{document}

You can add more tricks, depending in what you want to achieve, slightly changing the definition of \RA and \RB you can create automatic links to Wikipedia articles or insert images. This is much quicker than using DBtools and much more flexible.

48
  1. A very useful one is that \romannumeral expands everything on its way until it finds an integer. If the integer is negative, it expands to nothing. This can be used to fully expand something as follows:

    \def\a{\b}\def\b{\c}\def\c{\d}\def\d{1}
    \expandafter\show\romannumeral-`\0\a
    

    Here -`0 is not a complete number (it needs a space to become minus the character code of 0), so TeX looks ahead, expanding tokens as it goes. The code will show 1. On the other hand, \expandafter\show\romannumeral0\a would lead to some surprises: after a few expansions, \a yields 1, and TeX is now seeing \romannumeral01, which will expand to i (or something else if more digits lie ahead). (Thanks egreg for the comment.)

  2. I also like the combination of \afterassignment and \futurelet to read two tokens ahead. For instance,

    \newcommand{\readhead} [2]
      {\afterassignment\@gobble\futurelet#1{#2}}
    

    will set #1 equal to the first token of the list of tokens #2, then remove #2 from the input stream.

  3. Testing if a given token is either -, +, a digit, or something else:

    \newcommand{\test}[1]{%
      \ifcase\numexpr1\noexpand#11\relax
            % -
      \or   % other
      \or   % +
      \else % digit
      \fi}
    

    Replace \noexpand by \string if the goal is to test the character code of a character instead (regardless of category code), assuming that \escapechar is not too crazy.

  4. Test if a character is a letter.

    \ifnum\numexpr\uccode`#1/26=3 True\else False\fi
    

    Of course this breaks if someone plays around with uppercase codes.

  5. Test if a character is a digit.

    \ifnum 9<1#1 True\else False\fi
    
12
  • So in the first case, does that mean that \romannumeral-`\0 will keep expanding until it hits a space token? Jun 3, 2011 at 10:13
  • 1
    @Andrew Until an unexpandable token is found; if this token is a space token, it's ignored.
    – egreg
    Jun 3, 2011 at 10:48
  • @Bruno Perhaps you can add why -\0 is used instead of a simple 0: in your example if \d` expands to 1, with your construction 1 is found, with \romannumeral0 a surprise would hit the user.
    – egreg
    Jun 3, 2011 at 10:50
  • 11
    I just want to say that I find all of these appalling but fascinating, like quicksand or certain Australian spiders.
    – Ryan Reich
    Nov 4, 2011 at 17:19
  • 1
    For the digit testing one has to make sure that the argument is only one token that is not a macro expanding to multiple tokens to be reliable. Else one could get the argument 2aa which would result in the output aa True.
    – Skillmon
    Sep 27, 2018 at 18:11
39

One of my favorite kinds of trick is

\begingroup
<assignments>
\def\x{\endgroup<something>}\x

or variations thereof. For example (from the LaTeX kernel)

\begingroup
  \catcode`P=12
  \catcode`T=12
  \lowercase{
    \def\x{\def\rem@pt##1.##2PT{##1\ifnum##2>\z@.##2\fi}}}
  \expandafter\endgroup\x
\def\strip@pt{\expandafter\rem@pt\the}

that could actually be simplified into

\begingroup
  \catcode`P=12
  \catcode`T=12
  \lowercase{\endgroup\def\rem@pt#1.#2PT}{#1\ifnum#2>\z@.#2\fi}
\def\strip@pt{\expandafter\rem@pt\the}

It takes a little bit of thinking to understand how this works. Such uses of \lowercase or \uppercase are abundant in Heiko Oberdiek's packages (which are full of other cunning tricks).

Another variation on the same theme, added after having seen Danie Els's answer. It's not necessary to define globally the active period by saying

\begingroup
  \lccode`\~=`\.
  \lowercase{\endgroup
    \def\unitcenterdot{\mathcode`\.=\string"8000 \def~{\,{\cdot}\,}}}
\protected\def\unit#1{%
    \begingroup\unitcenterdot
        \ensuremath{\mathrm{#1}}%
    \endgroup}
\protected\def\SI#1#2{\ensuremath{#1\,\unit{#2}}}

(the \string is to avoid problems with babel that may activate it). When \lowercase is executed, we have the definition

\def\unitcenterdot{\mathcode`\.=\string"8000 \def.{\,{\cdot}\,}}}

(but where the period is active). In this way we define the meaning of the active period only inside \unit. The commands are defined as robust: there is no problem in having them in arguments of other commands because there's no category code change, but at \write time TeX would find an active period that has no definition.

3
  • Alas, I am dense - what exactly do these do? Jun 3, 2011 at 13:56
  • @Dean: look at Danie Els's answer. With \unit{N.m} you get the correct centered dot. Of course siunitx does the same thing and much more generally.
    – egreg
    Jun 3, 2011 at 14:00
  • 1
    Variation: \begingroup <catcode-assignments> \@firstofone{\endgroup <things to tokenize under different catcode-régime> } Mar 2, 2020 at 8:39
37

I like all the catcode changes (do not understand them half the time :-). The following is a very simple function to typeset SI units where a . is made active in math mode and typed as \cdot

{\catcode`\.=13 \gdef.{{\cdot}}}
\newcommand*\unit[1]{%
    \begingroup%
        \mathcode`.="8000%
        \ensuremath{\mathrm{#1}}%
    \endgroup}
\newcommand*\SI[2]{\ensuremath{#1\,\unit{#2}}}

Then the code

\noindent$\unit{N}=\unit{kg.m.s^{-2}}$\qquad \SI{1.2\times10^2}{N.m}

gives

enter image description here

Another great math catcode one is code posted by the late Michael J Downes that will turn -> into shorthand for \rightarrow in math mode.

\makeatletter
\mathchardef\mathminus=\mathcode`\-
\begingroup\catcode`\-=13 \gdef-{\mathhyphen} \endgroup
\def\mathhyphen{\futurelet\foo\mhyphb}
\def\mhyphb{%
    \ifx\foo >\rightarrow \expandafter\@gobble
    \else \mathminus
    \fi}
\mathcode`\-="8000
\makeatother

Then

$x - y$ \qquad $x -> y$

Gives

enter image description here

23

One of my favorite tricks I learned, then stole, from Bruno Le Floch is \slantbox, as described in his post at Shear transform a "box". This nominally will take an argument and using \pdf... magic, slant it to the right (positive slant) or left (negative slant) to an arbitrary degree.

First, here is Bruno's magic code for your preamble:

\newsavebox{\foobox}
\newcommand{\slantbox}[2][.5]
  {%
    \mbox
      {%
        \sbox{\foobox}{#2}%
        \hskip\wd\foobox
        \pdfsave
        \pdfsetmatrix{1 0 #1 1}%
        \llap{\usebox{\foobox}}%
        \pdfrestore
      }%
  }

Now, just find creative ways to use it. Seems simple enough, but I have found it so versatile, as to use it in many of my answers. For many of them enumerated below, I will provide images.

  1. Provide slant for a font that has no slant: How can I use the slanted variant of the libertine font?

  1. Slant a letter to make it conform to an adjacent object: Victory symbol in Salamanca

  1. Alter a letter slant to better conform with traditional/historical expectations, such as the look of the Laplace transform operator: Is This Laplace Transform Symbol Available in LaTeX?

  1. Drawing boxes that conform to the slant of the italic text: Draw italic box as a placeholder (around a single letter) in a word

  1. Drawing in 3-D perspective: a) Plot 3D stacked squares with shadow, b) How do I display pi in LaTeX like Don?, c) Tikz - Perspective Letter, rotated writing, d) "Star wars" text effect and e) Placing text on face of 3d cube

enter image description here

  1. Simulating left-handed handwriting: Left handed writing

  1. Producing upright greek for any greek font: a) Upright Greek font fitting to Computer Modern and b) Math mode in document title

  1. Creating custom symbols that involve slant: Symbol inbetween "#" and "ff"

  1. Another cunning trick, having absolutely nothing to do with \slantbox, is a simple macro I developed for doing a bubble sort without the use of packages, as shown in this answer, Using LaTeX to compact a list of numbers

The macro itself is

\def\listterminator{9999}% SET TO *ANY* VALUE KNOWN NOT TO BE IN LIST (POSITIVE OR NEGATIVE)
\newcommand\bubblesort[1]{\def\sortedlist{}\sortlist#1,\listterminator,\relax}
\def\sortlist#1,#2,#3\relax{%
  \ifnum#2=\listterminator\relax%
    \edef\sortedlist{\sortedlist#1}%
  \else
    \ifnum#1<#2\relax%
      \edef\sortedlist{\sortedlist#1,}%
      \sortlist#2,#3\relax%
    \else%
      \let\tmp\sortedlist%
      \def\sortedlist{}%
      \expandafter\sortlist\tmp#2,#1,#3\relax%
    \fi%
  \fi%
}

It takes input like \bubblesort{1,2,11, 7, 4, 3} and produces the sorted result in a macro, \sortedlist, to the effect of 1,2, 3, 4, 7,11.

Similar code but fixing two issues of the above bubblesort:

  1. Infinite loop if two values in the list equal. This version drops the duplet.
  2. ! TeX capacity exceeded, sorry [parameter stack size=...] for big lists is fixed.

It also removes the need of the \listterminator by changing the check for the terminating values to an \ifx\undefined#2.

\def\bubblesort#1{\def\sortedlist{}\sortlist#1,\undefined,\relax}
\def\sortlist#1,#2,#3\relax{%
  \ifx\undefined#2%
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\edef\sortedlist{\sortedlist#1}}
  {%
    \ifnum#1<#2
      \expandafter\@firstoftwo
    \else
      \expandafter\@secondoftwo
    \fi
    {\edef\sortedlist{\sortedlist#1,}\sortlist#2,#3\relax}
    {%
      \ifnum#1=#2
        \expandafter\@firstoftwo
      \else
        \expandafter\@secondoftwo
      \fi
      {\sortlist#2,#3\relax}%
      {%
        \let\tmp\sortedlist
        \def\sortedlist{}%
        \expandafter\sortlist\tmp#2,#1,#3\relax
      }%
    }%
  }%
}
18

Iterating through lists is fairly common and allows for compact code when using an appropriate definition. I often find that dealing with head/tail elements in the list requires special care. Here's an example (using etoolbox, although it holds for most processors/parsers):

enter image description here

\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\newcommand{\printlist}[2][,]{%
  \renewcommand*{\do}[1]{#1##1}% How each item is processed
  \docsvlist{#2}}% Process CSV list
\begin{document}
$\printlist{1,2,3,4,5,6,7}$ \par
$\printlist[;]{a,b,c,d,e,f}$
\end{document}

Processing the list in this generic way - placing a delimiter/separator followed by the item - leaves the head with an unwanted delimiter. One way to get rid of this is to define a new delimiter that delays its use for one cycle:

enter image description here

\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\newcommand{\printlist}[2][,]{%
  \def\itemdelim{\def\itemdelim{#1}}% Item delimiter delayed by one cycle
  \renewcommand*{\do}[1]{\itemdelim##1}% How each item is processed
  \docsvlist{#2}}% Process CSV list
\begin{document}
$\printlist{1,2,3,4,5,6,7}$ \par
$\printlist[;]{a,b,c,d,e,f}$
\end{document}

At the first cycle and call to \do, \itemdelim redefines itself so that it effectively sets nothing. At subsequent calls to \do, \itemdelim is fully-defined and just sets the delimiter.

Of course, this could be extended to whatever delay you want (not just a single cycle).

The alternative would be do condition on setting the delimiter based on the number of elements up to a certain point. Although intuitive, this is a little more cunning and uses TeX's macro expansion to its advantage.

3
  • How does this work if \printlist is called within a macro? Will this be expanded correctly?
    – normanius
    Mar 11 at 1:43
  • @normanius: It depends on the macro.
    – Werner
    Mar 11 at 3:35
  • True, it depends. I figured this out in this question.
    – normanius
    Mar 11 at 4:33
8

Some tricks:

Instead of

\expandafter\first
\expandafter\second
\expandafter\third
\expandafter\fourth
\expandafter\fifth
\expandafter\sixth
\expandafter\seventh
\expandafter\eighth
\expandafter\ninth
\expandafter\tenth
\eleventh

you can in many situations do:

\newcommand\exchange[2]{#2#1}

\expandafter\exchange\expandafter{\eleventh}{%
   \first\second\third\fourth\fifth\sixth\seventh\eighth\ninth\tenth
}

Instead of

\expandafter\expandafter\expandafter\first
\expandafter\expandafter\expandafter\second
\expandafter\expandafter\expandafter\third
\expandafter\expandafter\expandafter\fourth
\expandafter\expandafter\expandafter\fifth
\expandafter\expandafter\expandafter\sixth
\expandafter\expandafter\expandafter\seventh
\expandafter\expandafter\expandafter\eighth
\expandafter\expandafter\expandafter\ninth
\expandafter\expandafter\expandafter\tenth
\eleventh

you can do:

\newcommand\exchange[2]{#2#1}

\expandafter\first
\expandafter\second
\expandafter\third
\expandafter\fourth
\expandafter\fifth
\expandafter\sixth
\expandafter\seventh
\expandafter\eighth
\expandafter\ninth
\expandafter\tenth
\romannumeral0%
\exchange{ }{\expandafter\expandafter\expandafter}\eleventh

or

\newcommand\exchange[2]{#2#1}

\expandafter\exchange\expandafter{%
  \romannumeral0%
  \exchange{ }{\expandafter\expandafter\expandafter}\eleventh
}{%
  \first\second\third\fourth\fifth\sixth\seventh\eighth\ninth\tenth
}

Assume you wish the second token to be expanded before processing/expanding the first token.

You might do: \expandafter\first\second.

Now assume you wish K-level-expansion of the second token to have taken place before processing/expanding the first token.

With K=1 you can place 1 \expandafter before \first:

\expandafter\first
\second

With K=2 you can place 3 \expandafter before \first:

\expandafter\expandafter
\expandafter\first
\second

With K=3 you can place 7 \expandafter before \first:

\expandafter\expandafter
\expandafter            \expandafter
\expandafter\expandafter
\expandafter            \first
\second

With K=L you can place ∑i=1..L(2L-i)=∑i=1..L(2i-1)=2L-1 \expandafter before \first.

This way the amount of \expandafter that needs to be placed before \first increases exponentially.

Using nested \romannumeral-expansion, which takes its toll on the semantic nest, you can also have a linear increase of the amount of tokens needed:

\@ifdefinable\stopromannumeral{\chardef\stopromannumeral=`\^^00}%

K=1 - 1-level-expansion of \second shall have taken place before processing/expanding \first:

\expandafter\first
\second

K=2 - 2-level-expansion of \second shall have taken place before processing/expanding \first:

\expandafter\first
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\second

K=3 - 3-level-expansion of \second shall have taken place before processing/expanding \first:

\expandafter\first
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\second

K=4 - 4-level-expansion of \second shall have taken place before processing/expanding \first:

\expandafter\first
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\second

K=5 - 5-level-expansion of \second shall have taken place before processing/expanding \first:

\expandafter\first
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\second

K=6 - 6-level-expansion of \second shall have taken place before processing/expanding \first:

\expandafter\first
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
\second

Get the picture?

For K-level-expansion of \second you need (K-1) instances of
\romannumeral\expandafter\expandafter\expandafter\stopromannumeral
between \expandafter\first and \second.



\expandafter\endcsname-trick:

Assume you have foo and bar and baz and wish to get the sequence \foo\bar\baz, consisting of the tokens \foo and \bar and \baz.
This does the trick:

\csname foo\expandafter\endcsname
\csname bar\expandafter\endcsname
\csname baz\endcsname


Assume you need to construct a control-sequence-token from its name but don't like to combine \csname..\endcsname with "\expandafter-orgies":

Maybe the macro \CsTokenFromCsName is your friend:

\makeatletter
\@ifdefinable\CsTokenFromCsName{%
  \long\def\CsTokenFromCsName#1#{\romannumeral\InnerCsTokenFromCsName{#1}}%
}%
\newcommand\InnerCsTokenFromCsName[2]{%
  \expandafter\exchange\expandafter{\csname#2\endcsname}{0 #1}%
}%
\newcommand\exchange[2]{#2#1}%
\makeatother

\CsTokenFromCsName{foobar}\foobar
\CsTokenFromCsName\newcommand{foobar}...\newcommand\foobar...
\CsTokenFromCsName\global\long\def{foobar}...\global\long\def\foobar...
\CsTokenFromCsName\meaning{foobar}\meaning\foobar
\CsTokenFromCsName\string{foobar}\string\foobar
\CsTokenFromCsName\CsTokenFromCsName\global\let{foo}={bar}
      \CsTokenFromCsName\global\let\foo={bar}
      \global\let\foo=\bar



A nice tool for tail-recursive macros is \PassFirstToSecond, defined as \newcommand\PassFirstToSecond[2]{#2{#1}}:

Assume a tail-recursive macro which calls itself again and again, with modified arguments, until some termination-condition which depends on the tail-recursive macro's arguments is fulfilled.

You can nest calls to \PassFirstToSecond within \PassFirstToSecond's second argument in order to first modify the last argument as needed, then to modify the last but one argument as needed, then to modify the last but two argument as needed, etc.

Can look like this:

\newcommand\TailRecursiveMacro[9]{%
  \if⟨termination-condition that depends on #1..#9 is fulfilled⟩
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {%
    ⟨Things to do with #1..#9 in case termination-condition that depends on #1..#9  is fulfilled⟩%
  }{%
    % Prepare the next iteration as the termination-condition is not fulfilled:
    \expandafter\PassFirstToSecond\expandafter{%
      ⟨Things to do for obtaining the new argument #9, probably a \romannumeral0-expansion-thing⟩%
    }{%
      \expandafter\PassFirstToSecond\expandafter{%
        ⟨Things to do for obtaining the new argument #8, probably a \romannumeral0-expansion- thing⟩%
      }{%
        \expandafter\PassFirstToSecond\expandafter{%
          ⟨Things to do for obtaining the new argument #7, probably a \romannumeral0-expansion- thing⟩%
        }{%
          \expandafter\PassFirstToSecond\expandafter{%
            ⟨Things to do for obtaining the new argument #6, probably a \romannumeral0-expansion-thing⟩%
          }{%
            \expandafter\PassFirstToSecond\expandafter{%
              ⟨Things to do for obtaining the new argument #5, probably a \romannumeral0-expansion-thing⟩%
            }{%
              \expandafter\PassFirstToSecond\expandafter{%
                ⟨Things to do for obtaining the new argument #4, probably a \romannumeral0-expansion-thing⟩%
              }{%
               \expandafter\PassFirstToSecond\expandafter{%
                 ⟨Things to do for obtaining the new argument #3, probably a \romannumeral0-expansion-thing⟩%
                }{%
                  \expandafter\PassFirstToSecond\expandafter{%
                    ⟨Things to do for obtaining the new argument #2, probably a \romannumeral0-expansion-thing⟩%
                  }{%
                    \expandafter\PassFirstToSecond\expandafter{%
                      ⟨Things to do for obtaining the new argument #1, probably a \romannumeral0-expansion-thing⟩%
                    }{%
                      \TailRecursiveMacro
                    }%
                  }%
                }%
              }%
            }%
          }%
        }%
      }%
    }%
  }%
}%

The \romannumeral0-expansion-thingie is mentioned in Bruno Le Floch's answer.

You can combine this with an additional level of \romannumeral-expansion to ensure in expansion-contexts that regardless the amount of iterations the result will always be delivered after two expansion-steps/after two "hits" with \expandafter—can look like this:

\newcommand\TailRecursiveMacro[9]{%
  % Let's start \TailRecursiveMacro's \romannumeral-expansion:
  \romannumeral
  \if⟨termination-condition that depends on #1..#9 is fulfilled⟩
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {%
    % Let's stop  \TailRecursiveMacro's \romannumeral-expansion:
    0⟨space token⟩%
    ⟨Things to do/deliver with #1..#9 in case termination-condition that depends on #1..#9  is fulfilled⟩%
  }{%
    % Prepare the next iteration as the termination-condition is not fulfilled:
    \expandafter\PassFirstToSecond\expandafter{%
      ⟨Things to do for obtaining the new argument #9, probably a \romannumeral0-expansion-thing⟩%
    }{%
      \expandafter\PassFirstToSecond\expandafter{%
        ⟨Things to do for obtaining the new argument #8, probably a \romannumeral0-expansion- thing⟩%
      }{%
        \expandafter\PassFirstToSecond\expandafter{%
          ⟨Things to do for obtaining the new argument #7, probably a \romannumeral0-expansion- thing⟩%
        }{%
          \expandafter\PassFirstToSecond\expandafter{%
            ⟨Things to do for obtaining the new argument #6, probably a \romannumeral0-expansion-thing⟩%
          }{%
            \expandafter\PassFirstToSecond\expandafter{%
              ⟨Things to do for obtaining the new argument #5, probably a \romannumeral0-expansion-thing⟩%
            }{%
              \expandafter\PassFirstToSecond\expandafter{%
                ⟨Things to do for obtaining the new argument #4, probably a \romannumeral0-expansion-thing⟩%
              }{%
               \expandafter\PassFirstToSecond\expandafter{%
                 ⟨Things to do for obtaining the new argument #3, probably a \romannumeral0-expansion-thing⟩%
                }{%
                  \expandafter\PassFirstToSecond\expandafter{%
                    ⟨Things to do for obtaining the new argument #2, probably a \romannumeral0-expansion-thing⟩%
                  }{%
                    \expandafter\PassFirstToSecond\expandafter{%
                      ⟨Things to do for obtaining the new argument #1, probably a \romannumeral0-expansion-thing⟩%
                    }{%
                      % \TailRecursiveMacro's \romannumeral-expansion is already started.
                      % So via \expandafter\@gobble make sure that the next iteration does
                      % not also start \romannumeral-expansion:
                      \expandafter\@gobble\TailRecursiveMacro
                    }%
                  }%
                }%
              }%
            }%
          }%
        }%
      }%
    }%
  }%
}%


You can check whether an argument is empty as follows:

With e-TeX-extensions:

%%=============================================================================
%% Check whether argument is empty:
%%=============================================================================
%% \CheckWhetherNull{<Argument which is to be checked>}%
%%                  {<Tokens to be delivered in case that argument
%%                    which is to be checked is empty>}%
%%                  {<Tokens to be delivered in case that argument
%%                    which is to be checked is not empty>}%
\newcommand\CheckWhetherNull[1]{%
  \romannumeral0\if\relax\detokenize{#1}\relax
  \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {\@firstoftwo\expandafter{} \@firstoftwo}%
  {\@firstoftwo\expandafter{} \@secondoftwo}%
}%

Without e-TeX-extensions:

%%=============================================================================
%% Check whether argument is empty:
%%=============================================================================
%% \CheckWhetherNull{<Argument which is to be checked>}%
%%                  {<Tokens to be delivered in case that argument
%%                    which is to be checked is empty>}%
%%                  {<Tokens to be delivered in case that argument
%%                    which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\CheckWhetherNull[1]{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
  {\@firstoftwo\expandafter{} \@firstoftwo}%
}%


You can check whether a macro argument's first token is an explicit catcode-1(begin group)-character-token as follows:

%%-----------------------------------------------------------------------------
%% Check whether argument's first token is an explicit catcode-1-character:
%%.............................................................................
%% \CheckWhetherBrace{<Argument which is to be checked>}%
%%                   {<Tokens to be delivered in case that argument
%%                     which is to be checked has leading
%%                     catcode-1-token>}%
%%                   {<Tokens to be delivered in case that argument
%%                     which is to be checked has no leading
%%                     catcode-1-token>}%
\newcommand\CheckWhetherBrace[1]{%
  \romannumeral0\expandafter\@secondoftwo\expandafter{\expandafter{%
  \string#1.}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
  \@firstoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@secondoftwo}%
}%


If it is about token-sequences that don't contain curly braces/that do neither contain explicit catcode-1(begin group)-character-tokens, nor contain explicit catcode-2(end group)-character-tokens, then you can check by means of delimited arguments, i.e. by means of expansion only, whether an argument is/is not an element of a set of token-sequences/which element of the set of token-sequences the argument is.

Assume, you wish to check whether an argument either is empty or is A1 or is B2 or is C3 or is D4, and if so, which one it is:

The gist is:

Use a macro with argument-delimiter !!A1!B2!C3!D4! and see where the delimiter-matching takes place.

Of course you first need to ensure that the argument which is to be checked does not contain ! as otherwise the argument which is to be checked might contain the entire delimiter or might in erroneous ways complete the delimiter, which would lead to erroneous delimiter-matching:

\documentclass{article}
\makeatletter
% Use a definition of \CheckWhetherNull as presented above:
\newcommand\CheckWhetherNull[1]{%
  \romannumeral0\if\relax\detokenize{#1}\relax
  \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {\@firstoftwo{\expandafter}{} \@firstoftwo}%
  {\@firstoftwo{\expandafter}{} \@secondoftwo}%
}%
\@ifdefinable\GobbletoExclam{\long\def\GobbletoExclam#1!{}}%
\@ifdefinable\Forkfork{\long\def\Forkfork#1!!A1!B2!C3!D4!#2#3!!!!{#2}}%
\newcommand\Fork[7]{%
  % #1 - argument to check
  % #2 - tokens in case Argument is empty
  % #3 - tokens in case Argument is A1
  % #4 - tokens in case Argument is B2
  % #5 - tokens in case Argument is C3
  % #6 - tokens in case Argument is D4
  % #7 - tokens in case Argument is something else
  \expandafter\CheckWhetherNull\expandafter{\GobbletoExclam#1!}{%
    % #1 does not contain "!", so continue testing:
    \Forkfork!#1!A1!B2!C3!D4!{#2}% <- Argument #1 is empty
             !!#1!B2!C3!D4!{#3}% <- Argument #1 is A1
             !!A1!#1!C3!D4!{#4}% <- Argument #1 is B2
             !!A1!B2!#1!D4!{#5}% <- Argument #1 is C3
             !!A1!B2!C3!#1!{#6}% <- Argument #1 is D4
             !!A1!B2!C3!D4!{#7}% <- Argument #1 is something else without "!"
    !!!!%
  }{%
    #7% <- Argument #1 is something else with "!"
  }%

}%
\makeatother

\begin{document}

\Fork{}%
     {You have emptiness.}%
     {You have A1.}%
     {You have B2.}%
     {You have C3.}%
     {You have D4.}%
     {You have something else.}%

\Fork{A1}%
     {You have emptiness.}%
     {You have A1.}%
     {You have B2.}%
     {You have C3.}%
     {You have D4.}%
     {You have something else.}%

\Fork{B2}%
     {You have emptiness.}%
     {You have A1.}%
     {You have B2.}%
     {You have C3.}%
     {You have D4.}%
     {You have something else.}%

\Fork{C3}%
     {You have emptiness.}%
     {You have A1.}%
     {You have B2.}%
     {You have C3.}%
     {You have D4.}%
     {You have something else.}%

\Fork{D4}%
     {You have emptiness.}%
     {You have A1.}%
     {You have B2.}%
     {You have C3.}%
     {You have D4.}%
     {You have something else.}%

\Fork{!A1!B2!C3!D4!}%
     {You have emptiness.}%
     {You have A1.}%
     {You have B2.}%
     {You have C3.}%
     {You have D4.}%
     {You have something else.}%

\Fork{E5}%
     {You have emptiness.}%
     {You have A1.}%
     {You have B2.}%
     {You have C3.}%
     {You have D4.}%
     {You have something else.}%

\end{document}

enter image description here

(Be aware that with the trick above no temporary assignment was performed and no \if..-primitive was used.)


Assume you have a list of L arguments and wish to keep/select only the K-th argument thereof while removing the other arguments from the token-stream.

I can offer the macro \KeepKthOfLArguments:

\documentclass{article}

\makeatletter
%% Code for \KeepKthOfLArguments:
%%=============================================================================
\newcommand\PassFirstToSecond[2]{#2{#1}}%
%%=============================================================================
%% Check whether argument is empty:
%%=============================================================================
%% \CheckWhetherNull{<Argument which is to be checked>}%
%%                  {<Tokens to be delivered in case that argument
%%                    which is to be checked is empty>}%
%%                  {<Tokens to be delivered in case that argument
%%                    which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\CheckWhetherNull[1]{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
  {\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%%=============================================================================
%% Keep only the K-th of L consecutive undelimited arguments.
%%   ( IF K < 1 OR K > L just remove L consecutive undelimited arguments. )
%%=============================================================================
%% \KeepKthOfLArguments{<integer number K>}%
%%                     {<integer number L>}%
%%                     <sequence of L consecutive undelimited arguments>
%%
%% If L < 1 yields nothing.
%% Else:
%%   If K >= 1 and K < L  yields:
%%     <K-th undelimited argument from <sequence of L consecutive undelimited 
%%      arguments>>
%%   If K < 1 or K > L
%%     (-> there is no K-th argument in the
%%         <sequence of L consecutive undelimited arguments> )
%%   yields nothing  but removal of <sequence of L consecutive 
%%          undelimited arguments>
\newcommand\KeepKthOfLArguments[2]{%
  \romannumeral0%
  % #1: <integer number K>
  % #2: <integer number L>
  \expandafter\UD@KeepKthOfLArgumentsKSmallerOneFork
  \expandafter{\romannumeral\number\number#1 000\expandafter}%
  \expandafter{\romannumeral\number\number#2 000}%
}%
%%-----------------------------------------------------------------------------
\newcommand\UD@KeepKthOfLArgumentsKSmallerOneFork[2]{%
  % #1: <K letters m>
  % #2: <L letters m >
  \CheckWhetherNull{#1}{% K is smaller than one:
    \UD@KeepKthOfLArgumentsRemoveNArguments{#2}{ }{}%
  }{% K is not smaller than one:
    \expandafter\PassFirstToSecond
    \expandafter{%
      \@firstoftwo{}#1%
    }{%
      \UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop{#1}{#2}%
    }{#2}%
  }%
}%
%%-----------------------------------------------------------------------------
\newcommand\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop[4]{%
  % #1: <K letters m>  
  % #2: <L letters m>
  % (For detecting whether K>L or K<=L, during the loop letters m will
  %  be removed both from #1 and #2 until at least one of these arguments 
  %  is empty.
  %  When the loop terminates with 0<K<=L, #1 will be empty and #2
  %  will hold an amount of letters m corresponding to the the 
  %  difference L-K.
  %  When the loop terminates with K>L, #1 will not be empty and #2
  %  will be empty.
  % )
  % #3: <K-1 letters m>
  % #4: <L letters m>
  % (#3 and #4 will be left untouched during the loop so they can be 
  %  used for performing appropriate action when loop terminates as
  %  it is known whether K>L.)
  \CheckWhetherNull{#1}{% We have K<=L:
     \UD@KeepKthOfLArgumentsRemoveNArguments{%
       #3%
      }{%
       \UD@KeepKthOfLArgumentsRemoveNArguments{#2}{ }%
      }{}%
  }{%
    \CheckWhetherNull{#2}{% We have K>L:
      \UD@KeepKthOfLArgumentsRemoveNArguments{#4}{ }{}%
    }{% We don't know yet whether K<=L or K>L, thus remove letters m and 
      % do another iteration:
      \expandafter\PassFirstToSecond
      \expandafter{%
        \@firstoftwo{}#2%
      }{%
        \expandafter\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop
        \expandafter{%
          \@firstoftwo{}#1%
        }%
      }{#3}{#4}%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%% \UD@KeepKthOfLArgumentsRemoveNArguments{<N letters m>}%
%%                                        {<argument 1>}%
%%                                        {<argument 2>}%
%%                                        <sequence of consecutive 
%%                                         undelimited arguments>
%%.............................................................................
%% Removes the first N undelimited arguments from the <sequence of 
%% consecutive undelimited arguments>, then inserts  
%% <argument 1><argument 2>
%%
%% On the one hand when providing <argument 2> empty, you can use 
%% <argument 1> for nesting calls to \UD@KeepKthOfLArgumentsRemoveNArguments.
%% On the other hand you can provide a <space token> for stopping
%% \romannumeral-expansion as  <argument 1> and have the
%% macro grab the <K-th undelimited argument> from the <sequence of L 
%% consecutive undelimited arguments> as <argument 2>.
%%
\newcommand\UD@KeepKthOfLArgumentsRemoveNArguments[3]{%
  %% #1: <N letters m>  
  %% #2: <Argument 1>   
  %% #3: <Argument 2>
  \CheckWhetherNull{#1}{#2#3}{%
    \@firstoftwo{%
      \expandafter\UD@KeepKthOfLArgumentsRemoveNArguments
      \expandafter{%
        \@firstoftwo{}#1%
      }{#2}{#3}%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%% End of code for \KeepKthOfLArguments.
\makeatother

\begin{document}

\begin{verbatim}
\KeepKthOfLArguments{17}{30}%
  {Phrase 1}{Phrase 2}{Phrase 3}{Phrase 4}{Phrase 5}{Phrase 6}%
  {Phrase 7}{Phrase 8}{Phrase 9}{Phrase 10}{Phrase 11}{Phrase 12}%
  {Phrase 13}{Phrase 14}{Phrase 15}{Phrase 16}{Phrase 17}{Phrase 18}%
  {Phrase 19}{Phrase 20}{Phrase 21}{Phrase 22}{Phrase 23}{Phrase 24}%
  {Phrase 25}{Phrase 26}{Phrase 27}{Phrase 28}{Phrase 29}{Phrase 30}%
  . Something behind all the phrases.
\end{verbatim}

\KeepKthOfLArguments{17}{30}%
  {Phrase 1}{Phrase 2}{Phrase 3}{Phrase 4}{Phrase 5}{Phrase 6}%
  {Phrase 7}{Phrase 8}{Phrase 9}{Phrase 10}{Phrase 11}{Phrase 12}%
  {Phrase 13}{Phrase 14}{Phrase 15}{Phrase 16}{Phrase 17}{Phrase 18}%
  {Phrase 19}{Phrase 20}{Phrase 21}{Phrase 22}{Phrase 23}{Phrase 24}%
  {Phrase 25}{Phrase 26}{Phrase 27}{Phrase 28}{Phrase 29}{Phrase 30}%
  . Something behind all the phrases.

\bigskip

\noindent\hrulefill

\bigskip

\noindent\verb|\KeepKthOfLArguments| does deliver the result after two
expansion-steps:

\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \KeepKthOfLArguments{3}{11}{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}%
}%
\end{verbatim}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \KeepKthOfLArguments{3}{11}{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}%
}%

\noindent\texttt{\string\test: \meaning\test}%

\end{document}

enter image description here

(This will be continued in my second answer.)

2

(This is the continuation of my first answer.)

In case you wish to fork/select between more than seven phrases (which with the forking-trick as presented above, where one argument is needed for the thing to check and one argument is used for the "else"-case, would break the nine-argument-limit), you can combine the forking-trick and the select-K-th-of-L-arguments-trick:

\documentclass{article}

\makeatletter
%% Code for \KeepKthOfLArguments:
%%=============================================================================
\newcommand\PassFirstToSecond[2]{#2{#1}}%
%%=============================================================================
%% Check whether argument is empty:
%%=============================================================================
%% \CheckWhetherNull{<Argument which is to be checked>}%
%%                  {<Tokens to be delivered in case that argument
%%                    which is to be checked is empty>}%
%%                  {<Tokens to be delivered in case that argument
%%                    which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\CheckWhetherNull[1]{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
  {\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%%=============================================================================
%% Keep only the K-th of L consecutive undelimited arguments.
%%   ( IF K < 1 OR K > L just remove L consecutive undelimited arguments. )
%%=============================================================================
%% \KeepKthOfLArguments{<integer number K>}%
%%                     {<integer number L>}%
%%                     <sequence of L consecutive undelimited arguments>
%%
%% If L < 1 yields nothing.
%% Else:
%%   If K >= 1 and K < L  yields:
%%     <K-th undelimited argument from <sequence of L consecutive undelimited 
%%      arguments>>
%%   If K < 1 or K > L
%%     (-> there is no K-th argument in the
%%         <sequence of L consecutive undelimited arguments> )
%%   yields nothing  but removal of <sequence of L consecutive 
%%          undelimited arguments>
\newcommand\KeepKthOfLArguments[2]{%
  \romannumeral0%
  % #1: <integer number K>
  % #2: <integer number L>
  \expandafter\UD@KeepKthOfLArgumentsKSmallerOneFork
  \expandafter{\romannumeral\number\number#1 000\expandafter}%
  \expandafter{\romannumeral\number\number#2 000}%
}%
%%-----------------------------------------------------------------------------
\newcommand\UD@KeepKthOfLArgumentsKSmallerOneFork[2]{%
  % #1: <K letters m>
  % #2: <L letters m >
  \CheckWhetherNull{#1}{% K is smaller than one:
    \UD@KeepKthOfLArgumentsRemoveNArguments{#2}{ }{}%
  }{% K is not smaller than one:
    \expandafter\PassFirstToSecond
    \expandafter{%
      \@firstoftwo{}#1%
    }{%
      \UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop{#1}{#2}%
    }{#2}%
  }%
}%
%%-----------------------------------------------------------------------------
\newcommand\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop[4]{%
  % #1: <K letters m>  
  % #2: <L letters m>
  % (For detecting whether K>L or K<=L, during the loop letters m will
  %  be removed both from #1 and #2 until at least one of these arguments 
  %  is empty.
  %  When the loop terminates with 0<K<=L, #1 will be empty and #2
  %  will hold an amount of letters m corresponding to the the 
  %  difference L-K.
  %  When the loop terminates with K>L, #1 will not be empty and #2
  %  will be empty.
  % )
  % #3: <K-1 letters m>
  % #4: <L letters m>
  % (#3 and #4 will be left untouched during the loop so they can be 
  %  used for performing appropriate action when loop terminates as
  %  it is known whether K>L.)
  \CheckWhetherNull{#1}{% We have K<=L:
     \UD@KeepKthOfLArgumentsRemoveNArguments{%
       #3%
      }{%
       \UD@KeepKthOfLArgumentsRemoveNArguments{#2}{ }%
      }{}%
  }{%
    \CheckWhetherNull{#2}{% We have K>L:
      \UD@KeepKthOfLArgumentsRemoveNArguments{#4}{ }{}%
    }{% We don't know yet whether K<=L or K>L, thus remove letters m and 
      % do another iteration:
      \expandafter\PassFirstToSecond
      \expandafter{%
        \@firstoftwo{}#2%
      }{%
        \expandafter\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop
        \expandafter{%
          \@firstoftwo{}#1%
        }%
      }{#3}{#4}%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%% \UD@KeepKthOfLArgumentsRemoveNArguments{<N letters m>}%
%%                                        {<argument 1>}%
%%                                        {<argument 2>}%
%%                                        <sequence of consecutive 
%%                                         undelimited arguments>
%%.............................................................................
%% Removes the first N undelimited arguments from the <sequence of 
%% consecutive undelimited arguments>, then inserts  
%% <argument 1><argument 2>
%%
%% On the one hand when providing <argument 2> empty, you can use 
%% <argument 1> for nesting calls to \UD@KeepKthOfLArgumentsRemoveNArguments.
%% On the other hand you can provide a <space token> for stopping
%% \romannumeral-expansion as  <argument 1> and have the
%% macro grab the <K-th undelimited argument> from the <sequence of L 
%% consecutive undelimited arguments> as <argument 2>.
%%
\newcommand\UD@KeepKthOfLArgumentsRemoveNArguments[3]{%
  %% #1: <N letters m>  
  %% #2: <Argument 1>   
  %% #3: <Argument 2>
  \CheckWhetherNull{#1}{#2#3}{%
    \@firstoftwo{%
      \expandafter\UD@KeepKthOfLArgumentsRemoveNArguments
      \expandafter{%
        \@firstoftwo{}#1%
      }{#2}{#3}%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%% End of code for \KeepKthOfLArguments.

%% Code for forking:
\@ifdefinable\GobbletoExclam{\long\def\GobbletoExclam#1!{}}%
\@ifdefinable\Forkfork{\long\def\Forkfork#1!!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!#2#3!!!!{#2}}%
\newcommand\Fork[1]{%
  % #1 - argument to check
  \KeepKthOfLArguments{%
    % Let's use the \Forkfork-mechanism for obtaining K:
    \expandafter\CheckWhetherNull\expandafter{\GobbletoExclam#1!}{%
      % #1 does not contain "!", so continue testing:
      \Forkfork
      !#1!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{1}% <- Argument #1 is empty
      !!#1!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{2}% <- Argument #1 is AA
      !!AA!#1!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{3}% <- Argument #1 is BB
      !!AA!BB!#1!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{4}% <- Argument #1 is CC
      !!AA!BB!CC!#1!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{5}% <- Argument #1 is DD
      !!AA!BB!CC!DD!#1!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{6}% <- Argument #1 is EE
      !!AA!BB!CC!DD!EE!#1!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{7}% <- Argument #1 is FF
      !!AA!BB!CC!DD!EE!FF!#1!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{8}% <- Argument #1 is GG
      !!AA!BB!CC!DD!EE!FF!GG!#1!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{9}% <- Argument #1 is HH
      !!AA!BB!CC!DD!EE!FF!GG!HH!#1!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{10}% <- Argument #1 is II
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!#1!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{11}% <- Argument #1 is JJ
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!#1!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{12}% <- Argument #1 is KK
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!#1!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{13}% <- Argument #1 is LL
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!#1!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{14}% <- Argument #1 is MM
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!#1!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{15}% <- Argument #1 is NN
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!#1!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{16}% <- Argument #1 is OO
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!#1!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{17}% <- Argument #1 is PP
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!#1!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{18}% <- Argument #1 is QQ
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!#1!SS!TT!UU!VV!WW!XX!YY!ZZ!{19}% <- Argument #1 is RR
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!#1!TT!UU!VV!WW!XX!YY!ZZ!{20}% <- Argument #1 is SS
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!#1!UU!VV!WW!XX!YY!ZZ!{21}% <- Argument #1 is TT
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!#1!VV!WW!XX!YY!ZZ!{22}% <- Argument #1 is UU
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!#1!WW!XX!YY!ZZ!{23}% <- Argument #1 is VV
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!#1!XX!YY!ZZ!{24}% <- Argument #1 is WW
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!#1!YY!ZZ!{25}% <- Argument #1 is XX
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!#1!ZZ!{26}% <- Argument #1 is YY
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!#1!{27}% <- Argument #1 is ZZ
      !!AA!BB!CC!DD!EE!FF!GG!HH!II!JJ!KK!LL!MM!NN!OO!PP!QQ!RR!SS!TT!UU!VV!WW!XX!YY!ZZ!{28}% <- Argument #1 is something else without "!"
      !!!!%
    }{%
      28% <- Argument #1 is something else with "!"
    }%
  }{28}% <- Kth of L with L = 28.
}%
\makeatother

\begin{document}

\Fork{}%
     {You have emptiness.}{You have AA.}{You have BB.}{You have CC.}{You have DD.}{You have EE.}%
     {You have FF.}{You have GG.}{You have HH.}{You have II.}{You have JJ.}{You have KK.}%
     {You have LL.}{You have MM.}{You have NN.}{You have OO.}{You have PP.}{You have QQ.}%
     {You have RR.}{You have SS.}{You have TT.}{You have UU.}{You have VV.}{You have WW.}%
     {You have XX.}{You have YY.}{You have ZZ.}{You have something else.}%

\Fork{HH}%
     {You have emptiness.}{You have AA.}{You have BB.}{You have CC.}{You have DD.}{You have EE.}%
     {You have FF.}{You have GG.}{You have HH.}{You have II.}{You have JJ.}{You have KK.}%
     {You have LL.}{You have MM.}{You have NN.}{You have OO.}{You have PP.}{You have QQ.}%
     {You have RR.}{You have SS.}{You have TT.}{You have UU.}{You have VV.}{You have WW.}%
     {You have XX.}{You have YY.}{You have ZZ.}{You have something else.}%

\Fork{RR}%
     {You have emptiness.}{You have AA.}{You have BB.}{You have CC.}{You have DD.}{You have EE.}%
     {You have FF.}{You have GG.}{You have HH.}{You have II.}{You have JJ.}{You have KK.}%
     {You have LL.}{You have MM.}{You have NN.}{You have OO.}{You have PP.}{You have QQ.}%
     {You have RR.}{You have SS.}{You have TT.}{You have UU.}{You have VV.}{You have WW.}%
     {You have XX.}{You have YY.}{You have ZZ.}{You have something else.}%

\Fork{X?X!}%
     {You have emptiness.}{You have AA.}{You have BB.}{You have CC.}{You have DD.}{You have EE.}%
     {You have FF.}{You have GG.}{You have HH.}{You have II.}{You have JJ.}{You have KK.}%
     {You have LL.}{You have MM.}{You have NN.}{You have OO.}{You have PP.}{You have QQ.}%
     {You have RR.}{You have SS.}{You have TT.}{You have UU.}{You have VV.}{You have WW.}%
     {You have XX.}{You have YY.}{You have ZZ.}{You have something else.}%

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .