I was puzzled ats \expandafter, and I started with simple observations. Here're AI-generated explanations.
The command \expandafter is a low-level TeX primitive that controls the order of macro expansion. Its job is to force the expansion of a token that is not immediately next to it.
In the provided code, \expandafter is used to ensure that the recursive call \rrep receives a concrete number as its first argument, rather than an unexpanded macro sequence.
Let's break down the key line from the \rrep macro:
\expandafter\rrep\expandafter{\number\numexpr#1-1\relax}{\rep{#2}}Normally, TeX expands tokens from left to right. Without \expandafter, TeX would try to execute \rrep and would pass the entire sequence {\number\numexpr#1-1\relax} as the first argument, which is not what we want.
Here's how the \expandafter commands work together:
- The first
\expandafteris encountered. It skips the next token (\rrep) and looks at the token after that, which is the second\expandafter. - The second
\expandafteris now being expanded. It skips the next token ({) and looks at the token after that, which is\number. - The
\number\numexpr#1-1\relaxsequence is then expanded. For example, if#1is4, this sequence is calculated and expands to the literal number3. - After these forced expansions, the token stream effectively becomes
\rrep{3}{\rep{#2}}. The\rrepmacro is now called with a simple number (3) as its first argument, which allows the\ifnumconditional check to work correctly on the next recursive step.
In short, \expandafter is essential here to perform the subtraction (\numexpr#1-1) and convert the result to a number (\number) before the recursive call to \rrep is made. This prevents an infinite loop and allows the counter to correctly decrement and eventually reach the base case (#1 <= 0).
I only know some basic resursion. Thinking that typst will replace LaTeX, I don't think I'll spend more time on this and the Expl3 syntax.