[Tex/LaTex] Nested \loop macro

loopsnesting

Please are there 'nestable' variants of Knuth's favourite looping macro \loop without the brace-scope introduced in the answer at nested loops. I am developing a package called loops, where I am collecting many loops (including a new \foreach and some weird looping macros).

\@tempcnta0 % LaTeX
\loop
  \advance\@tempcnta by1
  \ifnum\@tempcnta<3\relax
  \@tempcntb0
  \loop
    \advance\@tempcntb by1
    \ifnum\@tempcntb<4\relax
    \@namedef{w@\romannumeral\@tempcnta @\romannumeral\@tempcntb}{x}%
  \repeat
\repeat

Best Answer

My initial example, which I leave below did not allow the same loop macro to be nested but did allow declaration of (structurally identical) macros which could be nested one inside the other.

Here is a new version based on the same idea, but actually the coding is simpler and it does allow nesting of loops without having to pre-declare different loop names. The syntax of \nloop is as for plain TeX \loop except that \nloop and \repeat must each be followed by an identifying token, so they may be matched in nested cases.

The definition is hardly any more complicated than that of \loop and simpler than the version below

\def\nloop#1{%
  \def\nl@@p##1##2\repeat#1{%
  \def##1{##2\relax\expandafter##1\fi}%
   ##1\let##1\relax}%
\expandafter\nl@@p\csname nl@@p-\string#1\endcsname
}

and a full test document using this definition on the test case in the question. In this example I use the tokens \a and \b to identify the two loops, but the \a and \b are arbitrary, and don't need to be defined commands (you could use 1 and 2 for example).

\documentclass{article}

\begin{document}

\makeatletter

\def\nloop#1{%
  \def\nl@@p##1##2\repeat#1{%
  \def##1{##2\relax\expandafter##1\fi}%
   ##1\let##1\relax}%
\expandafter\nl@@p\csname nl@@p-\string#1\endcsname
}

\@tempcnta0 % LaTeX
\nloop\a
  \advance\@tempcnta by1
  \ifnum\@tempcnta<3\relax
  \@tempcntb0
  \nloop\b
    \advance\@tempcntb by1
    \ifnum\@tempcntb<4\relax
    \typeout{defining \expandafter\string\csname
w@\romannumeral\@tempcnta @\romannumeral\@tempcntb\endcsname}
    \@namedef{w@\romannumeral\@tempcnta @\romannumeral\@tempcntb}{x}%
  \repeat\b
\repeat\a


\end{document}

\newloop declaration version:

This doesn't let \loop be nested but it does let you define other macros that have essentially identical definitions, so you can nest \loopb inside a \loop and can make a \loopc if need be:


(/usr/share/texmf-dist/tex/latex/base/size10.clo)) (./lp.aux)
defining \w@i@i
defining \w@i@ii
defining \w@i@iii
defining \w@ii@i
defining \w@ii@ii
defining \w@ii@iii
(./lp.aux) )

\documentclass{article}

\begin{document}

\makeatletter

%\def\loop#1\repeat{\def\iterate{#1\relax\expandafter\iterate\fi}%
%  \iterate \let\iterate\relax}

\def\nloopx#1#2#3#4#5{repeat}
\def\nloopy#1#2#3#4#5{iterate}
\def\nloopz#1#2#3{%
\let#2\fi
\def#1##1#2{\def#3{##1\relax\expandafter#3\fi}#3\let#3\relax}}

\def\newloop#1{%
\expandafter\def\expandafter\@tempa\expandafter{%
\expandafter#1%
\csname\expandafter\nloopx\string#1\expandafter\endcsname
\csname\expandafter\nloopy\string#1\endcsname}%
\expandafter\nloopz\@tempa}

\newloop\loopb



\@tempcnta0 % LaTeX
\loop
  \advance\@tempcnta by1
  \ifnum\@tempcnta<3\relax
  \@tempcntb0
  \loopb
    \advance\@tempcntb by1
    \ifnum\@tempcntb<4\relax
    \typeout{defining \expandafter\string\csname
w@\romannumeral\@tempcnta @\romannumeral\@tempcntb\endcsname}
    \@namedef{w@\romannumeral\@tempcnta @\romannumeral\@tempcntb}{x}%
  \repeatb
\repeat


\end{document}
Related Question