为什么将 \foreach 与 \newtheorem 结合起来的代码不起作用?

为什么将 \foreach 与 \newtheorem 结合起来的代码不起作用?

这是一个示例文档。

\documentclass[a4paper]{amsart}

\usepackage{tikz}

\theoremstyle{definition}
\newtheorem{baseTheorem}{Base Theorem}[section]
\foreach \x in                                         % 1
    {conjecture, definition, example}                  % 2
    {\newtheorem{\x}[baseTheorem]{\MakeUppercase{\x}}} % 3

\begin{document}

\section{Even numbers}

\begin{definition}
    A number is called \emph{even} if its remainder on division by $2$ is zero.
\end{definition}

\begin{example}
    $2$ and $0$ are both even numbers.
\end{example}

\begin{conjecture}
    The sum of two even numbers is again an even number.
\end{conjecture}

\end{document}

此文档无法编译。它会产生以下错误:

! Undefined control sequence.
<argument> \x 

l.16    A
          number is called \emph{even} if its remainder on division by $2$ i...

但是,如果将编号为 1、2 和 3 的行替换为以下行...

\newtheorem{conjecture}[baseTheorem]{\MakeUppercase{conjecture}}
\newtheorem{definition}[baseTheorem]{\MakeUppercase{definition}}
\newtheorem{example}[baseTheorem]{\MakeUppercase{example}}

... 然后文档就可以编译了,看起来和我预期的一样。(我真正想要的是将“Conjecture”等的首字母大写,而不是整个单词,但这是另一个问题。)

此外,如果将第 1 行和第 3 行的原始版本\x更改为,则会得到不同的错误消息:\t

! Argument of \UseTextAccent has an extra }.
<inserted text> 
                \par 
l.16     A
           number is called \emph{even} if its remainder on division by $2$ ...

我推断问题可能是第三个参数\newtheorem被逐字记录下来,并且仅在排版单个定理环境时才进行评估。我尝试了以下方法:

\foreach \x in
    {conjecture, definition, example}
    {\def\uppercased\MakeUppercase{\x} \newtheorem{\x}[baseTheorem]{\uppercased}}

但它并没有解决问题:

! Undefined control sequence.
<argument> \uppercased 

l.16     A
           number is called \emph{even} if its remainder on division by $2$ ...

我能做些什么?

答案1

\newtheorem由于每个定理的设置都不是在定义点处,因此最后一个参数中的命令会被展开,因此每个定理都会尝试\x在循环结束后很长时间使用其标题中的命令。您需要更改求值的顺序,例如,这有效:

\documentclass[a4paper]{amsart}

\usepackage{pgffor}

\theoremstyle{definition}
\newtheorem{baseTheorem}{Base Theorem}[section]
\foreach \x in                                         % 1
    {conjecture, definition, example}                  % 2
    {\edef\tmp{\noexpand\newtheorem{\x}[baseTheorem]{\noexpand\MakeUppercase{\x}}}\tmp} % 3

\begin{document}

\section{Even numbers}

\begin{definition}
    A number is called \emph{even} if its remainder on division by $2$ is zero.
\end{definition}

\begin{example}
    $2$ and $0$ are both even numbers.
\end{example}

\begin{conjecture}
    The sum of two even numbers is again an even number.
\end{conjecture}

\end{document}

答案2

尽管大卫·卡莱尔已经给出了问题的技术原因(\x扩展为迟到)他的回答,你也可以使用内部.list使用的处理程序,但是\foreach

  • 没有对内容进行分组(这里不是问题,因为\newtheorem无论如何都定义了全局环境)并且
  • 可以与已经扩展的内容一起使用#1(而不是作为宏序列)。

代码

\documentclass[a4paper]{amsart}

\usepackage{pgffor}
\theoremstyle{definition}
\newtheorem{baseTheorem}{Base Theorem}[section]

\pgfkeys{/utils/my Foreach/.code={\newtheorem{#1}[baseTheorem]{\MakeUppercase{#1}}},
         /utils/my Foreach/.list={conjecture, definition, example}}

\begin{document}
\section{Even numbers}

\begin{definition}
    A number is called \emph{even} if its remainder on division by $2$ is zero.
\end{definition}

\begin{example}
    $2$ and $0$ are both even numbers.
\end{example}

\begin{conjecture}
    The sum of two even numbers is again an even number.
\end{conjecture}
\end{document}

答案3

正如 David 已经解释过的,您需要获取字符串,而不是\x扩展到字符串。使用 很容易expl3

\documentclass[a4paper]{amsart}
\usepackage{expl3}

\ExplSyntaxOn
% provide a "user interface"
\cs_set_eq:NN \Foreach \clist_map_inline:nn
\ExplSyntaxOff

\theoremstyle{definition}
\newtheorem{baseTheorem}{Base Theorem}[section]
\Foreach{conjecture, definition, example}
  {\newtheorem{#1}[baseTheorem]{\MakeUppercase{#1}}}

\begin{document}

\section{Even numbers}

\begin{definition}
    A number is called \emph{even} if its remainder on division by $2$ is zero.
\end{definition}

\begin{example}
    $2$ and $0$ are both even numbers.
\end{example}

\begin{conjecture}
    The sum of two even numbers is again an even number.
\end{conjecture}

\end{document}

在此处输入图片描述

答案4

(编辑) 2017:因为xint 1.1 (2014/10/28)这里需要\usepackage{xinttools}。代码已更新,以替换\usepackage{xint}初始答案。

David 解释了原因,这里是使用 的替代方法,使用包的pgffor(可扩展)实用程序\xintApplyUnbraced信特(是的,我在这里无耻地不断宣传它)。想必将来的某个软件包版本将包含更多工具和更用户友好的语法,例如使用逗号分隔的值列表。

\Action定义以空格开头:这样做是为了停止\xintApplyUnbraced总是试图扩展的东西;空间被吞噬,并且\xintApplyUnbraced会很开心。然后,当所有三个\newtheorem语句都准备好时,它们才会被执行。

请注意,它\xintApplyUnbraced是完全可扩展的,并且在某些情况下可以提供帮助。

每次使用都\xintApplyUnbraced需要一个\Action宏,没有为其保留名称,但文档可以反复使用,\Action每次都有新定义。我使用\def而不是, \newcommand因为\Action它更像是一个低级助手。

\documentclass[a4paper]{amsart}

\usepackage{xinttools}

\theoremstyle{definition}
\newtheorem{baseTheorem}{Base Theorem}[section]

% space at the start could be removed, but in some other situations
% it has its use. It means: don't execute the following code until
% all elements from the initial list have been fed to \Action

\def\Action #1{ \newtheorem{#1}[baseTheorem]{\MakeUppercase{#1}}}

\xintApplyUnbraced\Action{{conjecture}{definition}{example}} 

\begin{document}

\section{Even numbers}

\begin{definition}
    A number is called \emph{even} if its remainder on division by $2$ is zero.
\end{definition}

\begin{example}
    $2$ and $0$ are both even numbers.
\end{example}

\begin{conjecture}
    The sum of two even numbers is again an even number.
\end{conjecture}

\end{document}

输出:

为什么不进行 foreach 等

相关内容