32

This question was inspired by comment banter in this question. See title.

5
  • As I mentioned in my comment to the original question, the problem is that \expandafter is a primitive, and is therefore executed, whereas and \superexpandafter will be a macro and will itself need expansion. There are various approaches which need various numbers of expansions. Perhaps you might specify how many we're allowed? (I think something similar was discussed by the NTS while writing e-TeX, but as a potential primitive. Never happened, of course.)
    – Joseph Wright
    Commented Jan 1, 2011 at 19:39
  • 2
    [I use \ea for \expandafter in this comment.] The main problem is that in \ea\ea\ea \foo \ea\ea\ea \bar \baz, we can definitely not replace each \ea\ea\ea by a single macro separately. Maybe it would be possible to write something along the lines of \superexpandafter{permutation of [1,n]} that, when expanded (once? twice?), would yield the result of expanding the n following macros in a specific order. Then, we can hopefully use it in a sensible way, never preceeded by \expandafters. --- Of course, a primitive would be the nicest :). Commented Jan 1, 2011 at 21:33
  • @Bruno: Well, I'd say the replacement is possible; see my answer below. Commented Jan 2, 2011 at 11:04
  • @Hendrik: Good job to you and TH! I'm not yet fluent enough in delayed expansion. I will need to take some time, sit down, and think about these ideas :). Commented Jan 2, 2011 at 14:31
  • 1

8 Answers 8

21

(Sorry, this gets more of an essay than an answer.)

TH claims that "There's not really a good way to do this that takes arguments." Well, I thought the same, but Philippe's answer to the original question of Yiannis proved me wrong. I've used his ingenious \csname-idea for a \multexpafter command that takes the number of expansions as an argument. New: I've implemented a much more efficient version that allows 0-100 expansions.

The crucial feature of the \multexpafter command is that it always needs 3 steps to be fully expanded. (I believe less steps to be impossible, but feel free to prove me wrong; see above :-)) This is in contrast with 2^n-1 consecutive \expandafters that need n expansion steps. I want the following TeX code to work (compare the "Hello world" example in my answer to Yiannis question):

\def\a#1.{#1}
\def\b#1:{#1.}
\def\c#1,{#1:}
\def\d{Hello world!,}
\multexpafter4\a
\multexpafter4\b
\multexpafter1\c
\d

Explanation, starting in the end: The \multexpafter1 should expand the \d after \c once. This should happen before the expansion of \b, so the \multexpafter4 in front of \b expands the \multexpafter1... 4 times. Three of these expansion steps are needed to fully expand the \multexpafter1, the last steps then expands the \c once. Same for the \multexpafter4 in front of \a: It expands the \multexpafter4\b... 4 times; the last of these steps expands the \b once. More generally, use

\multexpafter{<3+n>}\a
\multexpafter{<m>}\b\c

to first expand \c m times and then \b n times before expansion of \a. Again, 3 of the 3+n expansion steps are needed to fully expand \multexpafter{<m>}; then the \multexpafter{<m>} is gone, and so the next n expansion steps act on the \b.


Here's the new implementation of \multexpafter (to be compiled with tex or pdftex). It uses e-TeX's \numexpr (which to me feels a bit like cheating):

\catcode`@=11
\let\expandafter@i\expandafter
\count255=1
\loop\ifnum\count255<200
    \edef\temp{\the\count255}
    \advance\count255 by 1
    \expandafter\def\csname expandafter@\romannumeral\count255\expandafter\endcsname
    \expandafter{\expandafter\expandafter
        \csname expandafter@\romannumeral\temp\endcsname \expandafter}%
\repeat
\def\expandafter@{}
\def\expandafter@e{\errmessage{Argument of \noexpand\multexpafter must be between 0 and 100}}
\def\multexpafter#1{\csname expandafter@\ifnum#1>100 e\else
    \csname expandafter@\ifnum#1=0 ii\else\romannumeral\numexpr2*#1\fi\fi\endcsname
    \endcsname\csname expandafter@\romannumeral#1\endcsname}
\catcode`@=12

\def\a#1.{#1}
\def\b#1:{#1.}
\def\c#1,{#1:}
\def\d{Hello world!,}
\multexpafter4\a
\multexpafter4\b
\multexpafter1\c
\d
\bye

Only a short explanation: In the loop I construct macros \expandafter@ii to \expandafter@cc for expanding up to 200 times. The 3 expansion steps of \multexpafter{<n>} are as follows: The first step yields the replacement text of the macro. In the second step the \csname is executed, which triggers

\csname expandafter@\romannumeral<n>\endcsname

to be expanded 2n times, which in turn executes the desired n expansions. The result of the second step is just the control sequence \expandafter@, which in the third step expands to nothing.


For further illustration, here's how Philippe's example looks like with \multexpafter:

\def\a{a}
\def\b{b}
\def\c{\C}\def\C{c}
\def\d{d}
\def\e{\E}\def\E{\ee}\def\ee{e}
\multexpafter3\def
\multexpafter3\temp
\multexpafter4{%
\multexpafter4\a
\multexpafter5\b
\multexpafter4\c
\multexpafter3\d
\e
}
\show\temp

For completeness, here's my old inefficient implementation for 0-6 expansions:

\catcode`@=11
\def\expandafter@one{\expandafter}
\def\expandafter@two{\expandafter\expandafter\expandafter}
\def\expandafter@three{\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter}
\def\expandafter@four{\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter}
\def\expandafter@five{\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter}
\def\expandafter@six{\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter}
\def\do@nothing{}
\def\do@nothing@{\errmessage{Argument of \noexpand\multexpafter must be between 0 and 6}}
\def\m@e@a#1{\ifcase#1
\expandafter\do@nothing \or
\expandafter\expandafter@one \or
\expandafter\expandafter@two \or
\expandafter\expandafter@three \or
\expandafter\expandafter@four \or
\expandafter\expandafter@five \or
\expandafter\expandafter@six \else
\expandafter @\fi}
\def\multexpafter#1{\csname do@nothing\expandafter@six\m@e@a
    \expandafter@five#1\expandafter@four\endcsname\m@e@a#1}
\catcode`@=12
17
  • Ha! 395 \expandafters executed for the hello world example. That's amazing.
    – TH.
    Commented Jan 2, 2011 at 12:57
  • For the record, mine uses 39 and the minimum number is 11: \ea\ea\ea\ea\ea\ea\ea\a\ea\ea\ea\b\ea\c\d. I wish TeX had a way to define expandable macros that were always expanded all the way. Something analogous to e-TeX's \protected prefix. Maybe an \expanded prefix: \expanded\def\foo{\bar} and then \expandafter\a\foo would be expanded like it would when "building an expanded token list (for \edef, \xdef, \message, \errmessage, \special, \mark, \marks, or when writing the token list for \write to a file), The e-TeX manual.
    – TH.
    Commented Jan 2, 2011 at 13:11
  • @TH.: Well, I didn't say it was efficient. But it is easier to use, isn't it? (The \expanded prefix sounds like an interesting idea indeed.) Commented Jan 2, 2011 at 13:53
  • I'm uncomfortable saying that either are easy to use. E.g., why is it \mea4\a\mea4\b\mea1\c\d? That is, why 4, 4, 1? What would it be if you wanted to reverse the expansion order of \a\b\c\d\e? 4, 4, 4, 1? I guess that's it. I'm starting to see how this works. Once you get to expanding the \csname ... \endcsname, you get complete expansion. I wonder if this can be simplified using Joseph's \romannumeral trick.
    – TH.
    Commented Jan 2, 2011 at 21:47
  • 1
    @TH.: I'm down to 48, or 6n-2 for \mea{<n>}, with much shorter code, but using \numexpr. I'm ready to post it soon. Commented Jan 4, 2011 at 14:55
11

(I apologize for the length of this answer.)

There's not really a good way to do this that takes arguments. There are two reasons for this. The first is that it adds more tokens that have to be skipped over. For example, consider \sea{3}. If you need to skip over this, there's no simple way to get over those three tokens, at least not using another \sea. Even if you omit the braces, there's still one extra token.

The second reason has to do with implementing this. Consider

\let\ea\expandafter
\def\sea#1{%
        \ifcase#1
        \or \ea
        \or \ea\ea\ea
        \or \ea\ea\ea\ea\ea\ea\ea
        \fi
}

This is the obvious first choice, but that doesn't really work; consider \sea1. It'll expand to the \ifcase ... \fi and then if the \ifcase is expanded next, it'll expand to \ea\or \ea\ea\ea...\fi and then if the \ea is next, it'll skip the \or, start expanding a whole series of other \ea. To deal with this, you have to add yet more \eas in the definition to make it to the next \or or the \fi. It quickly becomes totally unworkable.

You can sort of use

\let\ea\expandafter
\def\seai{%
        \ea
}
\def\seaii{%
        \ea\ea\ea
}
\def\seaiii{%
        \ea\ea\ea\ea\ea\ea\ea
}
\def\seaiv{%
        \ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea
}
\def\seav{%
        \ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea
        \ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea\ea
}

But it's not extremely easy to use or follow.

\def\a{A}
\def\b{B}
\def\c{C}
\def\d{D}

\tracingall
\seai\a\b

\seaii\a\seai\b\c

\seaiii\a\seai\b\c

\seaiv\a\seaiii\b\seai\c\d

\seav\a\seaiii\b\seai\c\d
\bye

The first line expands \b and then \a. The second line expands \c, \a, then \b. The third line expands \c, \b, \a. The third expands \d, \c, \a, then \b. The fourth expands \d, \c, \b, \a. You can verify this by reading the log.

This can be simplified somewhat by not using \seai and just using \ea because then it doesn't have to be expanded twice to have the effect.

Edit:
After having played with this a bit. A pattern emerges. Using appropriate definitions, you can use

\seavii\a\seav\b\seaiii\c\seai\d\e

to expand \e, \d, \c, \b, and finally \a. Using \seavi instead of \seavii swaps the order of \a and \b. Other expansion orders are possible by changing the values, but it's not immediately obvious (at least it isn't to me) what a particular order will do.

For example, guess what

\seavi\a\seaiv\b\seaii\c\seai\d\e

will do.

Edit 2:
It's possible to get TeX to create the various \seaX macros for us rather than the error-prone manual method above.

\def\seai{\expandafter}
\count255 1
\loop\ifnum\count255<20
        \expandafter\let\expandafter\temp\csname
        sea\romannumeral\count255\endcsname
        \advance\count255 1
        \expandafter\gdef\csname sea\romannumeral\count255\expandafter
        \expandafter\expandafter\endcsname\expandafter\expandafter
        \expandafter{\expandafter\temp\temp\expandafter}%
\repeat
1
  • I love the recorded evolution of your answer. Thanks. Commented Jan 2, 2011 at 9:51
11

[Again, not really answering the question but posing an alternative.]

Nowadays, rather than attempting to repeat \expandafter in unreadable (and unmaintainable) chains, I recommend using the expl3 programming environment to deal with complex expansion problems.

Here's an example:

\exp_args:Nooo \foo \a \b \c

Here, \foo is not expanded (the N in the exp_args command) and \a, \b, \c are all expanded once (the o letters). But this isn't exactly how expl3 is intended to be used; instead, one would define that foo takes, say, five arguments by first defining \foo:nnnnn and then creating a variant for which each argument would be expanded once before execution of the function:

\usepackage{expl3}
\ExplSyntaxOn
\cs_set:Nn \foo:nnnnn { ...#1...#3...#5... }
\cs_generate_variant:Nn \foo:nnnnn {ooooo}
...
   \foo:ooooo \a \b \c \d \e
...
\ExplSyntaxOff

As well as o (for ‘expand once’) there are other argument specifiers such as V (value of macro or register), c (create a csname), x (complete expansion), f (‘romannumeral’ expansion), and so on. Using this system allows programmers to bypass many of the problems involved with expansion in classical TeX programming.

3
  • Of course, behind the scenes the code does construct the appropriate chain of primitives :-)
    – Joseph Wright
    Commented Jan 5, 2011 at 7:01
  • This is a nice feature of expl3 indeed, but what happens if the arguments of \foo:ooooo take arguments themselves, such as in my stupid "Hello world" example? For me it's not straightforward how to do that in expl3. Commented Jan 5, 2011 at 9:55
  • @Hendrik In practise we've found that it's generally not very common at all to come across situations like this — and when it does happen, it possibly indicates that your code is too convoluted and would be more readable if split up :) (although sometimes that's impossible when you need an expandable solution). We're not saying that expl3 can do everything; its goal is to make common things easier by providing wrappers around patterns in common TeX programming that often require ‘tricks’. Commented Jan 6, 2011 at 1:03
10

EDIT2: the previous code was broken when given conditional text as an input. I think this should be better. Also, the explanations were confusing. Now, for all the explanations below I \let\ea\expandafter. But not in the code.

TOC: Explanations ("Two user commands", "How it works"). Code ("Implementation", "Tests").

Explanations

Two user commands

  • For n>0, \MultiExpand{n}\macro gives the n-th expansion of \macro after two steps of expansion.

  • For n>0, \MultiExpandAfter{10}\macroA\MultiExpandAfter{4}\macroB\macroC expands \macroC 4 times before expanding \macroB 8=10-2 times, and finally \macroA. It also requires two steps.

The first expansion of \MultiExpand yields a very useful sequence of tokens: expanding \unless\ifcsname\multiexpand\fi{n} once expands the following token n times. The same exists for expanding after.

These are especially useful when we want to expand several times a very specific token which is buried behind many others. Example: after \def\macroA{\macroY\macroZ}, the code

\MultiExpand{5}\expandafter\macroA\expandafter\macroB%
\unless\ifcsname\multiexpandafter\fi{4}\macroC\macroD

will expand \macroD 4 times, then will expand \macroA 4=5-1 additional times. Also, these tokens can be used to force expansion of an expandable macro, more or less like TH. was asking for: just prepend it the macro with the relevant few tokens.

Note: if you really need \MultiExpand{0}, just do \empty\empty.

How it works

\unless\ifcsname expands tokens fully until it reaches \endcsname. If the control sequence thus built exists, then it jumps to the matching \fi and eats it. All this happens in one step: try \ea\def\ea\foo\ea{\unless\ifcsname let\endcsname \fi}. Since \let exists, \foo becomes empty. Try removing \unless. Then the conditional becomes true, and the \fi remains: the full expansion would require two steps. We will always arrange for this conditional to be false, to get rid of the \fi. Since it is much easier to ensure that a command exists than not, we use \unless\ifcsname ifcsname\endcsname\fi.

Now, as I said before, \ifcsname expands tokens. The trick is to put the various tokens that we want to expand between the \ifcsname and the matching \endcsname. The simplest example is \unless\ifcsname\endifcsname:. In one step, it expands to the empty token list, and additionally expands its argument once. If you think about it, (almost) everything is just as if these three tokens were not there.

This is in fact how the construction ends. Let us quickly look at the definition of \multiexpand:n, whose argument k is the number of expansion left to do. If k=1, we end the \ifcsname as described in the paragraph above, throwing away two last lines in braces (I hide this fact at the end of the macro name \endifcsname:n). Otherwise, we keep the two lines in braces: they do one step of expansion (\numexpr#1-1\expandafter), and leave \multiexpand:n{k-1} on the stream. It will be expanded, since we are still inside the construction of the cs name for \ifcsname.

The code

Implementation

% I follow the LaTeX3 convention of finishing each macro name by its
% argument specification, e.g. ":nnnN" for three braced arguments and
% one single token. For this, I need "_" and ":" to be letters.
\catcode`\:=11\relax%
\catcode`\_=11\relax%
\def\use:n#1{#1}%
\def\endifcsname:{ifcsname\expandafter\endcsname\expandafter\fi}%
\def\endifcsname:n#1{\endifcsname:}%
\def\endifcsnameafter:n#1{\endifcsname:\expandafter}%
%
% The user commands are \MultiExpand and \MultiExpandAfter.
\def\MultiExpand{\unless\ifcsname\multiexpand\fi}%
\def\multiexpand\fi{\multiexpand:n}%
\def\multiexpand:n#1{%
  \ifnum#1<2 \expandafter \endifcsname:n%
  \else      \expandafter \use:n%
  \fi%
  {\expandafter \multiexpand:n \expandafter {%
      \number\numexpr#1-1\expandafter}}%
}% 
% Almost identical definitions for expanding after...
\def\MultiExpandAfter{\unless\ifcsname\multiexpandafter\fi}%
\def\multiexpandafter\fi{\multiexpandafter:n}%
\def\multiexpandafter:n#1{%
  \ifnum#1<2 \expandafter\endifcsnameafter:n%
  \else      \expandafter \use:n%
  \fi%
  {\expandafter \multiexpandafter:n \expandafter {%
      \number\numexpr#1-1\expandafter}\expandafter}%
}%
\catcode`\_=8\relax%
\catcode`\:=12\relax%

Tests

There is no limit on the number of expansions.

% ======= Tests =====
\long\gdef\expandonce#1{% redefines #1 as #1 expanded once.
  \long\edef#1{\unexpanded\expandafter\expandafter\expandafter{#1}}}

% Commands that expand to each other, to count how many times things 
% were expanded.
\def\0{\1}    \def\1{\2}    \def\2{\3}    \def\3{\4}    \def\4{\5}
\def\5{\6}    \def\6{\7}    \def\7{\8}    \def\8{\9}    \def\9{\0x}

% Test \MultiExpand, after two expansions, 
% we get the 2011th expansion of \0.
\def\:{\MultiExpand{2011}\0}    \show\:
\expandonce\:                \show\:
\expandonce\:                \show\:

% Test \MultiExpandAfter, two expansions to get the specified expansion.
% The results also show that the expansion happens in the expected order.
\def\:{%
  \MultiExpandAfter{27}\0% note that we get \5xx (25=27-2).
  \MultiExpandAfter{14}\0% note that we get \2x (12=14-2).
  \MultiExpandAfter{38}\0\0}% note that we get \8xxx... no "-2".
\show\: 
\expandonce\:                  \show\:
\expandonce\:                  \show\:

For comparison, the "Hello World!" example

\def\a#1.{#1}
\def\b#1:{#1.}
\def\c#1,{#1:}
\def\d{Hello world!,}
\MultiExpandAfter3\a
\MultiExpandAfter3\b
\MultiExpandAfter1\c
\d

now uses 32 \expandafters, slightly better than Hendrik's solution (however, we should count the overhead with all the \csname and friends). The other example on which Hendrik was optimizing, namely, expanding seven tokens once each in the reverse order, takes 74 \expandafter:

\def\a{a}    \def\b{b}    \def\c{c}    \def\d{d}
\def\e{e}    \def\f{f}    \def\g{g}

\begingroup\tracingall
\MultiExpandAfter3\a    \MultiExpandAfter3\b
\MultiExpandAfter3\c    \MultiExpandAfter3\d
\MultiExpandAfter3\e    \MultiExpandAfter1\f\g
\endgroup

Some experimentation tells me that the number of \expandafter is roughly 5 times the sum of the arguments of the various \MultiExpandAfter.

13
  • @Bruno: Very nice, though I'm only slowly understanding it. A question and two comments: 1. The trick is that \unless\ifcsname ifcsname\endcsname\else\blubb\fi gives the full expansion of \blubb in one step, correct? 2. "expanding seven tokens once each": If you were alluding to Philippe's example, then it's 0 to 3 expansions. 3. In the comments to this answer of Philippe, Philippe asked if it would be worth putting this in a package. (Then it should be your version.) Commented Feb 13, 2011 at 17:00
  • @Hendrik: I am rewriting my answer above. 1. No, see the update above in an hour or so. 2. I was alluding to a comment of yours: "For the record, \seaxi\a\seaix\b\seavii\c\seav\d\seaiii\e\seai\f\g uses 2724 \expandafters, \mea4\a\mea4\b\mea4\c\mea4\d\mea4\e\mea1\f\g uses 818." I don't quite understand how many times each token \a,...\g is expanded in that example. 3. I will make it into a package some time next week, depending on where the Uppercase discussion on LaTeX-L goes. Commented Feb 13, 2011 at 18:22
  • @Bruno: 2. Ah, OK, now I got it. Thanks! Of course, in that example each token is expanded once. Commented Feb 13, 2011 at 18:26
  • @Bruno: You saw, no HTML, only markdown in comments. Use ** for bold. Moreover, inline code mustn't be followed by a letter in comments :-( In answers it works; I guess you want \expandafter s (without the space) at least twice in your answer. Commented Feb 13, 2011 at 18:30
  • @Hendrik: I updated my answer. As far as I can tell, the number of \expandafter grows linearly, with a reasonably small constant. Thanks for the ** tip. How do you do short links (e.g. tex.stackexchange.com writes the full address)? Commented Feb 13, 2011 at 18:46
7

We first give a direct answer to the question. Later we give another, in our opinion much nicer, way to reverse the expansion of tokens.

The direct answer is given by the following code. In the first macro we make an expandable countdown counter which is used in the macro \expand, which expands to itself with a doubled argument (#2#2) with a decreased counter (\number\BSp@decnumber{#1})

\def\BSp@decnumber#1{%
    \ifcase#1\or0\or1\or2\or3\or4\or5\or6\or7\or8\or9\or10
             \or11\or12\or13\or14\or15\or16\or17\or18\fi}

\def\expandafterN#1{\romannumeral-`X\expand{#1}\expandafter}

\def\expand#1#2{\ifnum#1=\z@\putafterfi{ }\else
    \putafterfi{\expandafter\expand
              \expandafter{\number\BSp@decnumber{#1}}{#2#2}#2}\fi}

\def\putafterfi#1#2\fi{\fi#1}

In this definition we use a trick described in Forcing full expansion. An expansion of \expandafterN{n} gives after two expansion 2^n-1 \expandafter's (the answer to the question).

Now we define some macros to show the order of expansion (see also the answer by Hendrik Vogt of Jan 2, 2011)

\def\a#1.{#1}
\def\b#1:{#1.}
\def\c#1,{#1:}
\def\d{Hello world,}

\edef\aaa{\expandafterN{10}\a\expandafterN6\b\expandafterN2\c\expandafter\d\e}
\show\aaa

This gives in the output window

> \aaa=macro:
->Hello world.
l.153 \show \aaa

exactly what we want. Note that for every extra token that we want to expand in reversed order, we need to increase the counter by 4. This seems not to much, but essentially, at every step the number of \expandafter's is multiplied by 16.

For another way to reverse the order of expansion we use the same trick, but now directly. Note that for reversing the order of expansion of n tokens, we only need 4(n-1) \expandafter's and (n-1) \romannumeral's.

\edef\aaa{\romannumeral-`X\expandafter\expandafter\expandafter\space\expandafter\a
          \romannumeral-`X\expandafter\expandafter\expandafter\space\expandafter\b
          \romannumeral-`X\expandafter\expandafter\expandafter\space\expandafter\c
          \romannumeral-`X\expandafter\expandafter\expandafter\space\expandafter\d
          \e}%

which again gives the desired result. As inserting the tokens

 \romannumeral-`X\expandafter\expandafter\expandafter\space\expandafter 

may obscure the TeX code, we can at the cost of more (namely 2n-5)) \expandafter's define the macro

\def\RNexpandafter{%
   \romannumeral-`X\expandafter\expandafter\expandafter\expandafter
                   \expandafter\expandafter\expandafter\space
                   \expandafter\expandafter\expandafter}%

\edef\aaa{\RNexpandafter\a\RNexpandafterRN\b\RNexpandafter\c\expandafter\d\e}

which again gives the desired result.

3
  • \romannumeral-&#x60;X also gobbles a space, thus \romannumeral-&#x60;X\expandafter\foo will expand \foo until it gobbles a space or meets an unexpandable token. Thus something like \romannumeral-&#x60;X\expandafter\space\expandafter\foo is needed. (&#x60; means the grave accent U+0060.) Commented Aug 18, 2013 at 16:24
  • @Heiko Thanks for pointing out the error. The code is adjusted according to the comment.
    – Jan-Kees
    Commented Aug 18, 2013 at 18:52
  • If not wanting to remove a space, doing \romannumeral\expandafter\stopromannumeral with \stopromannumeral being a <chardef token> denoting 0 instead of \romannumeral-`\expandafter\space\expandafter\foo is shorter. Commented Feb 27 at 11:02
3

In OpTeX, we can use \fornum 1..\expr[0]{2^#1-1}:

\def\superexpandafter#1{%
   \expanded{%
      \immediateassignment\def\tmp{}%
      \fornum 1..\expr[0]{2^#1-1}\do{\immediateassignment\addto\tmp{\ea}}%
   }\tmp
}

%% Tests:
\def\X{\Y} \def\Y{\Z} \def\Z{?}
\def\test#1{\wterm{\unexpanded{parameter is #1}}}

\superexpandafter{0}\test\X  % prints: parameter is \X
\superexpandafter{1}\test\X  % prints: parameter is \Y
\superexpandafter{2}\test\X  % prints: parameter is \Z
\superexpandafter{3}\test\X  % prints: parameter is ?

%% this is equivalent to:

                      \test\X  % prints: parameter is \X
\ea                   \test\X  % prints: parameter is \Y
\ea\ea\ea             \test\X  % prints: parameter is \Z
\ea\ea\ea\ea\ea\ea\ea \test\X  % prints: parameter is ?

\bye

Another solution runs loop only from 1 to n and doubles the number of \ea in each loop step. We have 2^n \eas in the resulting \tmp macro, so we remove one \ea using \ignoreit.

\def\superexpandafter#1{%
   \expanded{%
      \immediateassignment\def\tmp{\ea}%
      \fornum 1..#1\do{\immediateassignment\edef\tmp{\unexpanded\ea\ea\ea{\ea\tmp\tmp}}}%
   }\ea\ignoreit\tmp
}
2

n in your question seems to denote two different things:

  1. A variable within the mathematical expression 2n - 1. The value domain of that variable is not specified.
  2. A constellation of tokens which forms the argument of the macro-token \superexpandafter.

With the following considerations the focus is on 1., i.e., on n denoting a variable within a mathematical expression.

As you wish to obtain an amount of tokens \expandafter, the mathematical expression 2n - 1 is to represent a number of the kind "number of pieces", i.e., a non-negative integer.

There are also non-integer values ​​for n, where the expression 2n - 1 represents a non-negative integer. Nevertheless, for the sake of avoiding things like calculating binary logarithms by means of TeX, i.e., for the sake of making maths and programming and thus life easier, I assume that the value domain of n is formed by a closed interval of integers whose lower limit is 0. ;-)

If n is large, then 2n - 1 \expandafter are a lot of \expandafter.
For the thing to work out, these need to fit into TeX's memory.

First let's remember some complicated ;-) maths:
Fact 1: 2(0) - 1 = 0.
Fact 2: (2(k) - 1) · 2 + 1 = 2(k+1) - 1.

I.e., you can get 2n - 1 tokens \expandafter by recursively doubling the amount of already accumulated \expandafter and adding an \expandafter.
Begin the recursion with having already accumulated 0 tokens \expandafter (which is 2(k) - 1 tokens \expandafter for the case k = 0) and do the recursion n times.

You can use \romannumeral for this.

In the following example, with two "hits" by \expandafter, the expansion-cascade coming from the macro \superexpandafter{⟨number denoting the value n⟩} produces 2n - 1 tokens \expandafter.

If you want these \expandafter-tokens in a way, where the expansion-cascade works out with just one "hit" by \expandafter, then use \romannumeral\startsuperexpandafterloop{⟨number denoting the value n⟩}, where \romannumeral needs to be "hit" by one \expandafter for the expansion-cascade to produce the desired 2n - 1 tokens \expandafter.

In any case, if using \superexpandafter{⟨number denoting the value n⟩} or \romannumeral\startsuperexpandafterloop{⟨number denoting the value n⟩}, then ensure that in unusual circumstanced with non-standard \lccode-régime and/or non-standard \uccode-régime things like \uppercase or \lowercase won't interfere before the \expandafter-tokens are delivered—these primitives might turn ⟨digit⟩-tokens into non-⟨digit⟩-tokens and this way distort the process of gathering the tokens that belong to the ⟨number denoting the value n⟩. Or even worse—e.g., after \uccode`\1 =`\9 % \uppercase{1} turns 1 into 9 … ;-)

%%----------------------------------------------------------------------
%% \romannumeral\startsuperexpandafterloop{<number n>}%
%%  ->   delivers 2^n-1 tokens "\expandafter".
%%
%% n is a non-negative integer.
%% <number n> is a TeX <number> which represents the value of
%% the non-negative integer n.
%%----------------------------------------------------------------------
\chardef\stopromannumeral=`\^^00 %
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\innerdfork#1d#2#3dd{#2}%
\def\dfork#1{\innerdfork#1{\firstoftwo}d{\secondoftwo}dd}%
\def\startsuperexpandafterloop#1{%
  \expandafter\superexpandafterloop\expandafter{\expandafter}%
  \romannumeral\number\number#1 000d%
}%
\def\superexpandafterloop#1#2{%
  \dfork{#2}{\stopromannumeral#1}{\superexpandafterloop{#1#1\expandafter}}%
}%
%%----------------------------------------------------------------------
\def\superexpandafter{\romannumeral\startsuperexpandafterloop}%

\newlinechar=`\^^J

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \superexpandafter{0}%
}%
\message{^^J^^Jn=0:^^J\string\test: \meaning\test}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \superexpandafter{1}%
}%
\message{^^J^^Jn=1:^^J\string\test: \meaning\test}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \superexpandafter{2}%
}%
\message{^^J^^Jn=2:^^J\string\test: \meaning\test}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \superexpandafter{3}%
}%
\message{^^J^^Jn=3:^^J\string\test: \meaning\test}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \superexpandafter{4}%
}%
\message{^^J^^Jn=4:^^J\string\test: \meaning\test}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \superexpandafter{5}%
}%
\message{^^J^^Jn=5:^^J\string\test: \meaning\test}

\bye

Messages on the console/in the .log-file:

n=0:
\test: macro:-> 

n=1:
\test: macro:->\expandafter 


n=2:
\test: macro:->\expandafter \expandafter \expandafter 


n=3:
\test: macro:->\expandafter \expandafter \expandafter \expandafter \expandafter
 \expandafter \expandafter 


n=4:
\test: macro:->\expandafter \expandafter \expandafter \expandafter \expandafter
 \expandafter \expandafter \expandafter \expandafter \expandafter \expandafter 
\expandafter \expandafter \expandafter \expandafter 


n=5:
\test: macro:->\expandafter \expandafter \expandafter \expandafter \expandafter
 \expandafter \expandafter \expandafter \expandafter \expandafter \expandafter 
\expandafter \expandafter \expandafter \expandafter \expandafter \expandafter \
expandafter \expandafter \expandafter \expandafter \expandafter \expandafter \e
xpandafter \expandafter \expandafter \expandafter \expandafter \expandafter \ex
pandafter \expandafter


But a command whose expansion-cascade producess 2n - 1 tokens \expandafter with two "hits" by \expandafter, so that 2n - 1; n = 2 tokens \expandafter, i.e., three tokens \expandafter, are needed for producing these two "hits", might not be as useful as a command where "hitting" with one \expandafter produces n "hits" with \expandafter.

I.e., a command which is about producing "hits" by \expandafter instead of being about producing tokens \expandafter.

This is what the following command \Expandtimes is about—the code is almost the same as that of \superexpandafterloop.
The only difference is the place of \stopromannumeral:

%%----------------------------------------------------------------------
%% Hit \romannumeral of the expression
%%   \romannumeral\Expandtimes{<number n>}<tokens>
%% by \expandafter once and  <tokens> is hit by \expandafter n times.
%%
%% I.e., you need only one \expandafter-chain to hit \romannumeral
%% instead of needing n \expandafter-chains each to hit <tokens>.
%%
%% n is a non-negative integer.
%% <number n> is a TeX <number> which represents the value of
%% the non-negative integer n.
%%----------------------------------------------------------------------
\chardef\stopromannumeral=`\^^00 %
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\innerdfork#1d#2#3dd{#2}%
\def\dfork#1{\innerdfork#1{\firstoftwo}d{\secondoftwo}dd}%
\def\Expandtimes#1{%
  \expandafter\Expandtimesloop\expandafter{\expandafter}%
  \romannumeral\number\number#1 000d%
}%
\def\Expandtimesloop#1#2{%
  \dfork{#2}{#1\stopromannumeral}{\Expandtimesloop{#1#1\expandafter}}%
}%
%%----------------------------------------------------------------------

\def\MacroNotExpanded{\OnceExpanded 1 }%
\def\OnceExpanded{\TwiceExpanded 2 }%
\def\TwiceExpanded{\ThreeTimesExpanded 3 }%
\def\ThreeTimesExpanded{\FourTimesExpanded 4 }%
\def\FourTimesExpanded{\FiveTimeExpanded 5 }

\newlinechar=`\^^J

\expandafter\def
\expandafter\test
\expandafter{%
  \romannumeral\Expandtimes{0}\MacroNotExpanded 0%
}%
\message{^^J^^Jn=0:^^J\string\test: \meaning\test}

\expandafter\def
\expandafter\test
\expandafter{%
  \romannumeral\Expandtimes{1}\MacroNotExpanded 0%
}%
\message{^^J^^Jn=1:^^J\string\test: \meaning\test}

\expandafter\def
\expandafter\test
\expandafter{%
  \romannumeral\Expandtimes{2}\MacroNotExpanded 0%
}%
\message{^^J^^Jn=2:^^J\string\test: \meaning\test}

\expandafter\def
\expandafter\test
\expandafter{%
  \romannumeral\Expandtimes{3}\MacroNotExpanded 0%
}%
\message{^^J^^Jn=3:^^J\string\test: \meaning\test}

\expandafter\def
\expandafter\test
\expandafter{%
  \romannumeral\Expandtimes{4}\MacroNotExpanded 0%
}%
\message{^^J^^Jn=4:^^J\string\test: \meaning\test}

\expandafter\def
\expandafter\test
\expandafter{%
  \romannumeral\Expandtimes{5}\MacroNotExpanded 0%
}%
\message{^^J^^Jn=5:^^J\string\test: \meaning\test}

\bye

Messages on the console/in the .log-file:

n=0:
\test: macro:->\MacroNotExpanded 0 

n=1:
\test: macro:->\OnceExpanded 1 0 

n=2:
\test: macro:->\TwiceExpanded 2 1 0


n=3:
\test: macro:->\ThreeTimesExpanded 3 2 1 0


n=4:
\test: macro:->\FourTimesExpanded 4 3 2 1 0


n=5:
\test: macro:->\FiveTimeExpanded 5 4 3 2 1 0

Be aware that with the above varianf of \Expandtimesloop the amount of tokens accumulated in the first argument increases exponentially.

With the following variant of \Expandtimesloop that amount increases linearly at the cost of by and by getting (n+1) \romannumeral-expansions simultaneously:

\def\Expandtimesloop#1#2{%
  \dfork{#2}{#1\stopromannumeral}{%
    \Expandtimesloop{\expandafter\expandafter\expandafter\stopromannumeral\romannumeral#1}%
  }%
}%

If you prefer simultaneous \csname-expansions instead, you can do:

\def\Expandtimesloop#1#2{%
  \dfork{#2}{#1\stopromannumeral}{%
    \Expandtimesloop{\csname expandafter\expandafter\expandafter\expandafter\endcsname#1}%
  }%
}%
2

This is how it is done in the tokcycle package, courtesy of some macros provided by Christian Tellechea.

In this context, we expand the argument a number of times specified by the optional argument to \addcytoks and then add those tokens to the end of the \cytoks token list. The syntax is \addcytoks[n]{<argument>}, where n can be an integer denoting the number of expansions, where no expansion is provided if the optional argument is omitted, and the argument is fully expanded if the optional argument is given as x.

\documentclass{article}
\usepackage[T1]{fontenc}
\newtoks\cytoks
\makeatletter
\def\tc@ifempty#1{\tc@testxifx{\expandafter\relax\detokenize{#1}\relax}}
\long\def\tc@exfirst#1#2{#1}
\long\def\tc@exsecond#1#2{#2}
\long\def\tc@testxifx{\tc@earg\tctestifx}
\long\def\tc@earg#1{\expandafter#1\expandafter}
\long\def\tc@xarg#1#2{\tc@earg#1{\expanded{#2}}}
\long\def\tctestifcon#1{#1\expandafter\tc@exfirst\else\expandafter\tc@exsecond\fi}
\long\def\tctestifx#1{\tctestifcon{\ifx#1}}
\long\def\tctestifnum#1{\tctestifcon{\ifnum#1\relax}}
% SUPPORT MACROS FOR TOKENIZED OUTPUT: \addcytoks[<expansion level>]{<arg>}
% (CONTRIBUTED BY CHRISTIAN TELLECHEA)
\def\addcytoks{\futurelet\nxttok\addcytoks@A}
\long\def\tc@addtotoks#1{\cytoks\expandafter{\the\cytoks#1}}
\def\addcytoks@A{\tctestifx{[\nxttok}\addcytoks@B\tc@addtotoks}
\long\def\addcytoks@B[#1]#2{\tc@ifempty{#1}\tc@addtotoks
{\tctestifx{x#1}{\tc@xarg\tc@addtotoks}{\addcytoks@C{#1}}}{#2}}
\def\addcytoks@C#1{\tctestifnum{#1>0}{\tc@earg\addcytoks@C
{\the\numexpr#1-1\expandafter}\expandafter}\tc@addtotoks}
\makeatother
\begin{document}
\def\a{\b}
\def\b{\c}
\def\c{\d}
\def\d{\e}
\def\e{\f}
\def\f{\g}
\def\g{\h}
\def\h{i}

\addcytoks{\a}
\addcytoks[1]{\a}
\addcytoks[2]{\a}
\addcytoks[3]{\a}
\addcytoks[4]{\a}
\addcytoks[5]{\a}
\addcytoks[6]{\a}
\addcytoks[7]{\a}
\addcytoks[8]{\a}
\addcytoks[9]{\a}

\detokenize\expandafter{\the\cytoks}
\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 .