Programmatically define macro within the body of \foreach

There are a few problems with your code. The first one, that generates the error, is that \foreach does (something equivalent to) \def\pgffor@body{<loop code>}, and if <loop code> contains a #, that will error (try it). The solution to this one is to double the #, so

\IfNoValueF{##1}{^{##1}}

then there will be no errors... but your commands won't work either :D

The first roadblock is that \foreach creates a group around the loop code, so local assignments are lost and, as you might have guessed by now, \NewDocumentCommand creates the command in a local scope (prepending \global to it won't work either), so after \foreach ends your commands won't exist anymore. \foreach is not a good choice to define commands (or programming tasks in general, in my opinion).

The second problem is that your commands are defined as (simplified):

\def\FF#1{\ensuremath {\mathbb {\letter }\IfNoValueF {#1}{^{#1}}}}
\def\NN#1{\ensuremath {\mathbb {\letter }\IfNoValueF {#1}{^{#1}}}}
\def\ZZ#1{\ensuremath {\mathbb {\letter }\IfNoValueF {#1}{^{#1}}}}
...

and what is \letter? Likely H, since it's the last value in the loop, but with recent versions of pgffor it's undefined (or something you don't expect).

My suggestion to defeat both problems in one go is to not use \foreach. Use instead a looping construct that doesn't do groups, and preferably allows the loop item to be #1 rather than a macro. expl3's \clist_map_inline:nn fits the bill:

\RequirePackage{xparse}
\ExplSyntaxOn
\clist_map_inline:nn { F,N,Z,Q,R,C,H }
  {
    \exp_args:Nc \NewDocumentCommand { #1#1 } { o }
      {\ensuremath{\mathbb{#1}\IfNoValueF{##1}{^{##1}}}}
  }
\ExplSyntaxOff

(\exp_args:Nc \macro { <tokens> } is \expandafter\macro\csname <tokens>\endcsname).


You don't mention it but I assume you are using the loop from pgf which places a group around each iteration. It's easier to use a different construct eg map over the list with expl3. enter image description here

\documentclass{article}
\usepackage{amsfonts}
\ExplSyntaxOn
\clist_map_inline:nn{F,N,Z,Q,R,C,H}{
    \expandafter\NewDocumentCommand\csname#1#1\endcsname{o}{\ensuremath{\mathbb{#1}\IfNoValueF{##1}{^{##1}}}}
}
\ExplSyntaxOff
\begin{document}

\FF  \FF[x]

\QQ  \QQ[2]

\ZZ \ZZ[\infty]

\end{document}

\documentclass{article}
\usepackage{amssymb,listofitems}
\def\ZZstencil#1#2\relax{%
  \mathbb{#1}\ifx\relax#2\relax\else^{#2}\fi
}
\def\ZZargs{[1][]}
\newcommand\makeZZ[1]{%
  \readlist\mylist{#1}%
  \foreachitem\z\in\mylist[]{%
    \expandafter\newcommand\csname\z\z\expandafter\expandafter
      \expandafter\endcsname\expandafter\ZZargs\expandafter{%
      \expandafter\ZZstencil\z####1\relax}%
  }%
}
\begin{document}

\makeZZ{F,N,Z,Q,R,C,H}
$\RR$
$\RR[a+b]$
$\ZZ$
$\ZZ[(a+b)/2]$
$\HH$$\HH[x]$
\end{document}

enter image description here

If you really need it to \ensuremath, then this:

\documentclass{article}
\usepackage{amssymb,listofitems}
\def\ZZstencil#1#2\relax{%
  \mathbb{#1}\ifx\relax#2\relax\else^{#2}\fi
}
\def\ZZargs{[1][]}
\newcommand\makeZZ[1]{%
  \readlist\mylist{#1}%
  \foreachitem\z\in\mylist[]{%
    \expandafter\newcommand\csname\z\z\expandafter\expandafter
      \expandafter\endcsname\expandafter\ZZargs\expandafter{%
      \expandafter\ensuremath\expandafter{\expandafter
      \ZZstencil\z####1\relax}}%
  }%
}
\begin{document}
\makeZZ{F,N,Z,Q,R,C,H}
\RR\ \RR[a+b]\ \ZZ\ \ZZ[(a+b)/2]\ $\HH\HH[x]$
\end{document}