在 \foreach 的主体内以编程方式定义宏

在 \foreach 的主体内以编程方式定义宏

我正在尝试编写一个宏\RR,允许我输入\mathbb{R}文本,并带有一个可选的指数参数。所需的功能如下所示:

I can now write \RR\ in text. % --> produces: I can now write $\mathbb{R}$ in text.
Blah blah \RR[m+n] blah blah. % --> produces: Blah blah $\mathbb{R}^{m+n}$ blah blah

对于固定字母(例如 R),目前可以通过以下方式实现:

\NewDocumentCommand{\RR}{o}{\ensuremath{\mathbb{R}\IfNoValueF{#1}{^{#1}}}}

我想为其他字母定义类似的命令。我意识到最实用的方法是为每个额外的字母编写上述版本。但是,出于学习目的,我很好奇如何使用\foreach。我尝试过类似

\foreach \letter in {F,N,Z,Q,R,C,H}{
    \expandafter\NewDocumentCommand\csname\letter\letter\endcsname{o}{\ensuremath{\mathbb{\letter}\IfNoValueF{#1}{^{#1}}}}
}

上述命令无法创建。尝试

I can now write \RR\ in text. % --> should produce: I can now write $\mathbb{R}$ in text.
Blah blah \RR[m+n] blah blah. % --> should produce: Blah blah $\mathbb{R}^{m+n}$ blah blah

Illegal parameter number in definition of \pgffor@body在定义点(内部foreach)产生错误,Undefined control sequence当我尝试使用\RR如上所示时。

至少,它似乎缺少了类似\expandafter\noexand的东西,我曾见过 用它\edef来控制 的扩展\ensuremath{\mathbb{\letter}\IfNoValueF{#1}{^{#1}}}。任何帮助都将不胜感激,谢谢!

答案1

您的代码存在一些问题。第一个会产生错误,即\foreach执行了(等同于)的操作\def\pgffor@body{<loop code>},如果<loop code>包含#,则会出现错误(尝试一下)。此问题的解决方法是将加倍#,因此

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

那么就不会有错误了...但是你的命令也不会起作用:D

第一个障碍是\foreach在循环代码周围创建一个组,因此本地分配会丢失,并且您现在可能已经猜到了,\NewDocumentCommand在本地范围内创建命令(\global在它前面添加也不起作用),因此\foreach结束后您的命令将不再存在。\foreach这不是定义命令(或者在我看来,一般的编程任务)的好选择。

第二个问题是您的命令定义为(简化):

\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}}}}
...

那么是什么\letter? 很有可能H,因为它是循环中的最后一个值,但是最新版本的pgffor它是未定义的(或者是您意想不到的东西)。

我建议一次性解决这两个问题,就是不要使用\foreach。而是使用不进行分组的循环构造,并且最好允许循环项而不是#1宏。 expl3符合\clist_map_inline:nn要求:

\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> }\expandafter\macro\csname <tokens>\endcsname)。

答案2

您没有提到,但我假设您使用的是 pgf 中的循环,该循环在每次迭代周围放置一个组。使用不同的构造(例如使用 expl3 映射列表)会更容易。 在此处输入图片描述

\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}

答案3

\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}

在此处输入图片描述

如果你真的需要它\ensuremath,那么这个:

\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}

答案4

我会用expl3它完成工作,但与其他答案的使用方式不同。

\documentclass{article}
\usepackage{amssymb}

\ExplSyntaxOn
\NewDocumentCommand{\makenumberset}{m}
 {
  \clist_map_inline:nn { #1 }
   {
    \cs_new_protected:cpn { ##1##1 } { \numberset { ##1 } }
   }
 }
\NewDocumentCommand{\numberset}{mo}
 {
  \ensuremath { \mathbb{#1}\IfValueT{#2}{^{#2}} }
 }
\ExplSyntaxOff

\makenumberset{F,N,Z,Q,R,C,H}

\begin{document}

In text \RR\ and \RR[m+n]; also in math $\RR$ and $\RR[m+n]$.

In text \ZZ\ and \ZZ[m+n]; also in math $\FF$ and $\FF[m+n]$.

And also \numberset{A} or \numberset{A}[m+n].

\end{document}

注意偶尔出现的字母的抽象命令。

在此处输入图片描述

我当然会不是使用它没有任何实际用途。能够输入文本,但有时必须记住后面的反斜杠,\ensuremath这没什么好处。有了它,您就不会遇到这个问题。\RR$\RR$

相关内容