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

You need to expand away the \fi

\RequirePackage{amsmath}

\makeatletter

\newcommand{\defset}[1]{\expandafter\newcommand\csname #1\endcsname{\mathbb{#1}}}
\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.


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}

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.

enter image description here

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).