尝试使用 \global 出了什么问题?

尝试使用 \global 出了什么问题?

这个问题我已经得到了一个复杂的方法来实现我所设定的目标。这个问题不是“我该怎么做”的问题——我已经有答案了——而是“请解释一下我尝试的方法有什么缺陷”的问题。

最初的问题是\crefnamecleveref 包提供的宏在 中没有任何效果\foreach。jfbu(在答案中)和 egreg(在评论中)指出,问题在于\crefname仅在本地产生影响,并且更改在每次循环迭代结束时都会被丢弃。在 egreg 发布提供解决方案的答案之前,我想到使用 来\foreach构建一个命令来执行\crefname更改,然后在循环结束后调用该命令。我使用\global宏使更改成为全局的。不幸的是,\global导致出现错误消息,我不知道为什么。这是我的尝试:

\documentclass[a4paper]{amsart}

\def\myTheoremEnvironments{%
    theorem/theorems,%
    cobblestone/cobblestones,%
    toybox/toyboxes%
}

\usepackage{tikz, titlecaps, cleveref}

% Number all definition, theorem, etc. environments using the same counter.
% Start counting again at the start of each section.
% Style these environments using LaTeX's "definition" style.
\theoremstyle{definition}
\newtheorem{baseTheorem}{Base Theorem}[section]
\def\mycrefnamecommands{}
\foreach \x/\y in \myTheoremEnvironments {
    \edef\tmp{\noexpand\newtheorem{\x}[baseTheorem]{\noexpand\titlecap{\x}}}\tmp
    \global\edef\mycrefnamecommands{\mycrefnamecommands\noexpand\crefname{\x}{\x}{\y}}
}
\mycrefnamecommands

\begin{document}

\section{Hello, and welcome to my document.}

\begin{cobblestone}
    \label{csref}
    Hello. I am an ``cobblestone'' environment.
\end{cobblestone}

\begin{toybox}
    \label{tbref}
    I am a ``toybox'' environment. What a strange name that is for an environment.
\end{toybox}

\begin{theorem}
    \label{thmref}
    People trying to do strange things with ``foreach'' should expect trouble.
\end{theorem}

Here are some references to \cref{csref}, \cref{tbref} and \cref{thmref}.
I could have tried using just one call to ``cref'' here,
but it's best not to run before you can walk.

\end{document}

这是错误消息。我尝试用谷歌搜索,但没有看到任何特别有用的结果。

! Argument of \@ynthm has an extra }.
<inserted text> 
                \par 
l.66 }

答案1

你必须记住\edef一路,但\noexpand只抑制一次扩展。因此,在第一次循环之后,的替换文本\mycrefnamecommands

\crefname{theorem}{theorem}{theorems}

而在第二个周期\edef就会试图扩张\crefname,从而引发灾难。

你必须小心,只扩大一次 \mycrefnamecommands在各个步骤中。这可以通过两种方式完成:

\toks0=\expandafter{\mycrefnamecommands}%
\xdef\mycrefnamecommands{\the\toks0 \noexpand\crefname{\x}{\x}{\y}%

\the\toks0利用由 产生的标记列表不会进一步扩展这一事实\edef\xdef与 相同\global\edef)。

另一种利用 e-TeX 扩展(在 LaTeX 中可用)的方法是

\xdef\mycrefnamecommands{%
  \unexpanded\expandafter{\mycrefnamecommands}%
  \noexpand\crefname{\x}{\x}{\y}%
}%

其功能与上面的基本相同,但仅需一步。

另一种策略可能是

\def\mycrefnamecommands{}
\foreach \x/\y in \myTheoremEnvironments {
  \let\crefname\relax
  \edef\tmp{\noexpand\newtheorem{\x}[baseTheorem]{\noexpand\titlecap{\x}}}\tmp
  \xdef\mycrefnamecommands{\mycrefnamecommands\crefname{\x}{\x}{\y}}
}
\mycrefnamecommands

\foreach循环中我们将其设置\crefname为等于\relax,因此它变得不可扩展,因此它不会以任何方式被解释\xdef;然而,在的末尾\foreach\crefname将恢复其原来的含义,因此在执行最终宏时\mycrefnamecommands它将定期完成其工作。

相关内容