# expl3 function for fixed number of expansion steps

In expl3, say we want to assign a value to a token list variable \l_foo_tl while expanding the value a certain number of times. For a single expansion the easiest way is

\tl_set:No \l_foo_tl { ... }


For more expansions we can use

\exp_args:NNo \tl_set:No \l_foo_tl { ... }
\exp_args:NNNo \exp_args:NNo \tl_set:No \l_foo_tl { ... }


and so on. This doesn't scale nicely, though. For four expansions we already have to use \exp_args_generate:n to generate proper expansion functions.

Does expl3 provide a generic, expandable function that, once tiggered by a single expansion step, expands its argument a given number of times exactly? If not, what is the most idiomatic way of doing such an expansion series in expl3?

• There isn't anything for an specific number of expansions, but most likely an f expansion does what you want here. The f expansion will expand the head of the token list (as will o) until the the head of the token list is an unexpandable token. – Phelype Oleinik May 27 at 23:25
• f expands too far in most of the cases. I'm debugging function definitions and actually want to get the results after a certain number of expansion steps. – siracusa May 27 at 23:34

There is now!

The LaTeX3 people will flay alive me when they see this :|

Here's an s-type expansion (s stands for “blame siracusa” for this ;-) that, unlike other expansion flavours, takes an argument. The argument is the number of expansions of o-type expansions of the token list. You need then to define your own \exp_args:N... commands that do the expansion of the argument. For example, to expand the first argument four times you can define:

\cs_new:Npn \exp_args:Niv { \::s {4} \::: }


or to f-expand the first, and expand the second two times:

\cs_new:Npn \exp_args:Nft { \::f \::s {2} \::: }


or the contrary (first→twice, second→f):

\cs_new:Npn \exp_args:Ntf { \::s {2} \::f \::: }


or yet expand some argument an arbitrary amount of times:

\cs_new:Npn \exp_times:nNs #1 { \::s {#1} \::: }


and so on. Here's the code and some proofs-of-functionality. I define a macro \a which expands to \b, \b to \c, and so on until \f expands to g (to count expansions easily):

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn
\cs_new:Npn \::s #1#2 \::: #3#4
{
\if_int_compare:w #1 > 0 ~
\exp_after:wN \exp_after:wN
\exp_after:wN \__siracusa_exp_step_s:nnnn
\else:
\exp_after:wN \__siracusa_exp_end_s:Nnnnn
\fi:
\exp_after:wN {#4} {#1} {#2} {#3}
}
\cs_new:Npn \__siracusa_exp_step_s:nnnn #1#2#3#4
{
\exp_after:wN \::s \exp_after:wN
{ \int_value:w \__int_eval:w #2-1 \__int_eval_end: } {#3} \::: {#4} {#1}
}
\cs_new:Npn \__siracusa_exp_end_s:Nnnnn #1#2#3#4#5
{ \__exp_arg_next:nnn {#2} {#4} {#5} }

% Examples
\cs_new:Npn \exp_times:nNs #1 { \::s {#1} \::: }
\cs_new:Npn \exp_times:nNnfso #1 { \::n \::f \::s {#1} \::o \::: }
\cs_new:Npn \weird_command:nnnn #1 #2 #3 #4
{ \tl_to_str:n {#1|#2|#3|#4} }
\ExplSyntaxOff

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

\begin{document}

\ttfamily

\ExplSyntaxOn
\exp_times:nNs {0} \tl_to_str:n { \a }\par
\exp_times:nNs {1} \tl_to_str:n { \a }\par
\exp_times:nNs {2} \tl_to_str:n { \a }\par
\exp_times:nNs {3} \tl_to_str:n { \a }\par
\exp_times:nNs {4} \tl_to_str:n { \a }\par
\exp_times:nNs {5} \tl_to_str:n { \a }\par
\exp_times:nNs {6} \tl_to_str:n { \a }\par

\exp_times:nNnfso {0} \weird_command:nnnn{\a}{\b}{\c}{\d}\par
\exp_times:nNnfso {1} \weird_command:nnnn{\a}{\b}{\c}{\d}\par
\exp_times:nNnfso {2} \weird_command:nnnn{\a}{\b}{\c}{\d}\par
\exp_times:nNnfso {3} \weird_command:nnnn{\a}{\b}{\c}{\d}\par
\exp_times:nNnfso {4} \weird_command:nnnn{\a}{\b}{\c}{\d}\par
\ExplSyntaxOff

\end{document}

• That's fantastic! I like how easily those argument types are composable by using the various \:: functions. So can I take it we'll see \::s in the next expl3 release, as you are going to secretly add it to the repo while the rest of the team is asleep? ;) – siracusa May 28 at 2:08
• @siracusa we never sleep – David Carlisle May 28 at 8:08
• @siracusa I doubt this would be useful for more than academic purposes. For everything else there is the f expansion. Of course, if you provide an use case, a feature request could be added. It would be fun, though, if I did that ;-) – Phelype Oleinik May 28 at 9:47
• @DavidCarlisle “The empire on which the sun never sets” ;-) – Phelype Oleinik May 28 at 9:58