# High-order recursive macro to define several similar macro at once does infinite loop

I’m a fan of factorization and hate code repetition. So I was trying to define a macro which defines for me all the common mathematical sets commands (\C, \N, etc.) and made a recursive function inspiring of \slowRomannumeral p. 24 from these TeX and LaTeX programmation notes.

So I did this first:

\def\defsets#1{\defnextset #1@}
\def\defnextset#1{\ifx @#1 \else
\expandafter\newcommand\csname #1\endcsname{\mathbb{#1}}
\expandafter\defnextset
\fi}
\defsets{RDNZQC}


But I soon realised that I needed something alike for my math operators, exactly the same but just with \DeclareMathOperator instead of \newcommand and without \mathbb, so I defined a \defset command and tried to make my main macro high-order:

\def\defsets#1{\defnext\defset #1@}
\def\defnext#1#2{\ifx @#2 \else
#1#2\relax
\expandafter\defnext#1
\fi}
\defsets{RDNZQC}



ERROR: Missing \endcsname inserted.

--- TeX said ---
\let
l.68 \defsets{RDNZQC}


and adding an \expandafter makes the same as the actual current code with \newcommand* (and all the same combinations with it): an infinite loop.

So how to make this code work? so I can just make a \defop and do the same thing for my math operators and some code tricks with each operator command between braces (since this currently works for single characters actually).

• in your second fragment did you mean \defnextset to be \defnext (which is used but not defined) – David Carlisle Mar 30 '16 at 14:23
• I corrected that before to see your comment sorry ^^" some mistakes after first question submission. – galex-713 Mar 30 '16 at 14:45
• I also updated the title (the error was not this one finally) – galex-713 Mar 30 '16 at 14:55

You cannot skip more than one token by one \expandafter. There are more solutions of your problem. For example, you can set the used def-method by \let first:

\def\defset#1{\expandafter\def\csname#1\endcsname{\mathbb{#1}}}

\def\defsets#1{\let\defnextA=\defset \defnext #1@}
\def\defnext#1{\ifx @#1\else
\defnextA{#1}%
\expandafter\defnext
\fi}

\defsets{RDNZQC}


Second: you can repeat the def-method as #1 but with one more \expandafter:

\def\defset#1{\expandafter\def\csname#1\endcsname{\mathbb{#1}}}

\def\defsets#1{\defnext\defset #1@}
\def\defnext#1#2{\ifx @#2\else
#1{#2}%
\expandafter\defnext\expandafter#1%
\fi}

\defsets{RDNZQC}


You need to expand away the \fi

\RequirePackage{amsmath}

\makeatletter

\def\defsets#1{\defnext\defset #1@}
\def\defnext#1#2{\ifx @#2%
\expandafter\@gobble
\else
#1{#2}%
\expandafter\@firstofone
\fi
{\defnext#1}}
\defsets{RDNZQ{Zzz}C}

\show\Z
\show\Zzz

\newcommand*{\defop}[1]{\expandafter\DeclareMathOperator\csname #1\endcsname{#1}}

\defnext\defop {Vect}{Spec}@

{\let\protect\show\Vect}

\stop


Produces

LaTeX2e <2016/03/31>
Babel <3.9q> and hyphenation patterns for 81 language(s) loaded.
> \Z=\long macro:
->\mathbb {Z}.
l.15 \show\Z

?
> \Zzz=\long macro:
->\mathbb {Zzz}.
l.16 \show\Zzz

?
> \Vect =\long macro:
->\qopname \newmcodes@ o{Vect}.
\Vect ->\protect \Vect

l.23 {\let\protect\show\Vect
}
?


Note you need to re-brace #2 as {#2} to support multiple token arguments.

• @galex-713 works for me, I updated with your mathoperator example. – David Carlisle Mar 30 '16 at 14:56
• Yes I just noticed what you said on rebracing #2 and I deleted my comment and accepted your answer. – galex-713 Mar 30 '16 at 15:00
• @galex-713 I saw the tick flash to wipet and back:-) oh no, and back again:( – David Carlisle Mar 30 '16 at 15:01
• Well I was going to ask him to add some of your changes like the \show and above all the rebracing of #2 before then noticed he did integrate them without highlighting them. – galex-713 Mar 30 '16 at 15:03
• @galex-713 I'll probably to survive without your 15 points:-) – David Carlisle Mar 30 '16 at 15:26

The problem is of course in \expandafter\defnext#1 that tries to expand whatever is replaced for #1 instead of the intended \fi.

If you hate code repetition, you'll surely like this, where \defsets and \defops are basically one-liners.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\defsets}{m}
{
\tl_map_inline:nn { #1 }
{
\cs_new_protected:cpn { ##1 } { \mathbb{##1} }
}
}
\NewDocumentCommand{\defops}{m}
{
\clist_map_inline:nn { #1 }
{
\galex_declaremathoperator:cn { ##1 } { ##1 }
}
}
\cs_set_eq:NN \galex_declaremathoperator:Nn \DeclareMathOperator
\cs_generate_variant:Nn \galex_declaremathoperator:Nn { c }
\ExplSyntaxOff

\defsets{RDNZQC}
\defops{Vect,Spec}

\begin{document}

\texttt{\meaning\R}

\texttt{\meaning\Q}

\texttt{\meaning\Spec}

\texttt{\expandafter\meaning\csname Spec \endcsname}

\end{document}


Only one \expandafter to show that \Spec does the right thing. None in the coding part.

I could have used

\exp_args:Nc \DeclareMathOperator { ##1 } { ##1 }


instead of defining \galex_declaremathoperator:Nn and a variant thereof. But this way all is cleaner and in line with recommendations.

The same is obtained with \@tfor:

\makeatletter
%\let\@xp\expandafter % already done by amsmath
\newcommand{\defsets}[1]{%
\@tfor\next:=#1\do{%
\@xp\newcommand\csname\next\@xp\endcsname\@xp{\@xp\mathbb\@xp{\next}}%
}%
}
\newcommand{\defops}[1]{%
\@tfor\next:=#1\do{%
\@xp\DeclareMathOperator\csname\next\@xp\endcsname\@xp{\next}%
}%
}
\makeatother

\defsets{RDNZQC}
\defops{{Vect}{Spec}}


The \@tfor function is essentially the abstract version of the \slowRomannumeral trick in your variant: it consumes one item at a time from the token list passed between := and \do, doing \def\next{<item>} (\next can be any token). The main difference is exactly this: we need to expand \next if we don't want that it is incorporated in the definition of \N and so on. Therefore the long chain of \expandafter's is needed. An item in this context is a single token or a braced group.

The \tl_map_inline:nn method is much better, because the current item is available “literally” as #1 (so in the body of a definition it must be called ##1).

• Omg I really need to learn to use this xparse and to become used of it… each time I see it it seems to me so verbose! kinda like Java… That seems a whole language on the top of TeX! is that already used in some packages? or internally within LaTeX? – galex-713 Mar 30 '16 at 20:52
• @galex-713 It is used in several packages. – egreg Mar 30 '16 at 20:59
• 8 hours ago when I answered I nearly put a comment starting a countdown to a map_inline answer from you:-) – David Carlisle Mar 30 '16 at 22:46
• Oh that’s interesting! I didn’t know about @tfor yet ^^" (I’ll be reading its source to try to understand it soon ^^), but well, I didn’t end your book yet ^^ but why all those \expandafter near the end of the line? (how can work the third-last and last while there’s no “second token” after it except the closing brace? and I’m working on how to make the \mathbb optionnal if no optional argument is given – galex-713 Apr 1 '16 at 8:48
• @galex-713 The following token, not group. So \expandafter{\next} expands \next before the { has its effect. – egreg Apr 2 '16 at 14:38

Seems I wake up after the battle, all dust has settled ...

\documentclass{article}
\usepackage{amsmath}
\usepackage{xinttools}

\makeatletter
\newcommand\defsets [1]
{\xintFor* ##1 in {#1} \do {\@namedef{##1}{\mathbb{##1}}}}
\makeatother

\newcommand\defops [1]
{\xintFor ##1 in {#1} \do {\expandafter
\DeclareMathOperator\csname ##1\endcsname{##1}}}

\defsets{RDNZQC}
\defops{Vect, Spec}

\begin{document}

\texttt{\meaning\R}

\texttt{\meaning\Q}

\texttt{\meaning\Spec}

\texttt{\expandafter\meaning\csname Spec \endcsname}

\end{document}


• you mean xinttools isn't an over-used package ?!?! that's shocking ! egreg himself says having the item "literally as #1" was (quote) much better ;-) Have you looked at TeX by Topic? – user4686 Apr 1 '16 at 9:12
• @galex-713 I was just making a little joke, as xinttools is my own package ;-) naturally great package xparse is much more used, in relation to the whole of expl3, programming layer of future LaTeX3. In contrast xinttools provides some random utilities à la Plain TeX, which were useful for me in other contexts. TeX by Topic is a well-known reference book for people who want to master TeX language; complementary to TeXBook. Reading it is good way to master the basics, so that you then understand what LaTeX3 is built upon, even if ultimately it will hide all of those roots. – user4686 Apr 1 '16 at 10:01
• @galex-713 I suspect one shouldn't say 'LaTeX3 is going to build on xparse', but from what I gather, presumably much of the syntax of xparse for the end-user will indeed be part of what LaTeX3 will offer. Please people correct me here if needed. (it is actually xparse which is built upon future LaTeX3 in a way) – user4686 Apr 1 '16 at 10:14
• @galex-713 the xparse syntax looks indeed different with the rest of legacy LaTeX, but it has strong justifications. Obviously, xparse is very powerful package and I think its facilities will be part of how LaTeX3 will do things for the end users. It greatly facilitates things for package authors as well who won't have to re-invent the wheel each time. – user4686 Apr 1 '16 at 10:18