我对这里的扩张方式感到困惑

我对这里的扩张方式感到困惑

我很高兴能想出一种方法tabular使用结构构建环境的内容\foreach \x in {...} {...}

但我很好奇到底需要什么才能破解我的代码。这是我的序言,适用于一般情况非复杂内容(无论其含义是什么):

\documentclass{article}
\usepackage[margin=0.5in]{geometry}
\usepackage{amsmath,amssymb,array}
\usepackage{booktabs}
\usepackage{etoolbox}
\usepackage{pgfkeys,pgffor}

\pgfkeys{/ae/agenda/.cd,
  items for the agenda/.initial=,
  title/.initial=,
} 
\def\aeset#1{\pgfkeys{/ae/agenda/.cd,#1}}
\def\aeget#1{\pgfkeysvalueof{/ae/agenda/#1}}

\makeatletter

\newcounter{agendaitemcounter}
\def\agenda@item@number{%%
  \stepcounter{agendaitemcounter}%%
  \arabic{agendaitemcounter}.)}

\def\full@agenda{}
\long\def\build@agenda{%%
  \foreach \x in \list@of@agenda@items {
    \xdef\full@agenda{%%
      \expandonce\full@agenda
      \expandonce\agenda@item@number
      \expandonce\aeamp
      \expandonce\x
      \noexpand\\
      \noexpand\midrule}
  }}

\def\setagenda#1{%%
  \bgroup
  \aeset{#1}%%
  \edef\list@of@agenda@items{\aeget{items for the agenda}}%%
  \build@agenda
  \begin{minipage}[t]{4in}\centering
    {\large \aeget{title}}%%
    \par\vspace{1ex}
    \begin{tabular}{cp{3in}}\toprule
      \full@agenda          \bottomrule
    \end{tabular}%%
  \end{minipage}%%
  \setcounter{agendaitemcounter}{0}%%
  \egroup
  \def\full@agenda{}%%
  }

\makeatother

\renewcommand{\arraystretch}{1.5}

\def\aeamp{&}
\def\aepar{\par}
\def\dollars#1{\$#1}%$
\def\mypoly{\[x^2+1\]}

\pagestyle{empty}

因此,我开始尝试一些东西来查看序言中的宏会在哪里中断:找到某些东西并不难。

下面的示例代码按照上面的序言编写,可以很好地编译(除了包含的一行注释掉的行\noexpand\par)。但是,如果我开始\noexpand从这些中删除命令在职的行,错误开始弹出。

我不太明白为什么某些结构不会破坏(例如\frac{...}{...}x^2\infty),而其他表面上相似或更简单的结构(例如\cos\$)会破坏我的代码。

\begin{document}

\setagenda{
  title={To-do list},
  items for the agenda={%%
    {Line of random content, but nothing too fancy.},
    {Not too involved math: $x\cdot y$ },
    {A bit more involved, but it works! $\displaystyle{}\frac{1}{2d}$ },
    { Random collection of math symbols: $\inf \infty x^2+x$ },
    %% I need to use `\noexpand` to avoid getting an error.
    {This line works!\noexpand\aepar Hello world }
    %%{This line fails!\noexpand\par Hello world }
    { what follows fails without \noexpand\texttt{noexpand}},
    { Trying something which covers multiple lines 
      \belowdisplayskip=0pt%%
      \belowdisplayshortskip=0pt%%
      \noexpand\mypoly
    },
    {Transfer \noexpand\dollars{3000} for trip to Venice},
    { $x\noexpand\cos(x)$ How many suitcases do I need?},
    { What's this going to result in? 
      \belowdisplayskip=0pt%%
      \belowdisplayshortskip=0pt%%
      \noexpand\[ x^2+1\noexpand\]
    }
  }%%
}

\vspace{1cm}

\setagenda{
  title={something else},
  items for the agenda={%%
    {first item},
    {second item}}}

\end{document}

为什么有些数学命令有效,而其他的无效。我认为,因为我正在发出\expandonce用于构建环境内容的宏tabular,所以不应该出现这些错误。

更详细地讲,当我尝试以微型视角观察这一现象时,在没有环境噪音的情况下tabular,我会更加困惑。

以下 MWE 可以编译:

\documentclass{article}
\usepackage{etoolbox}
\usepackage{pgffor}
\begin{document}
\let\mytrial\relax
\foreach \x in {$\cos$,
                $x^2+x$}
  {\xdef\mytrial{\x}}
\mytrial
\end{document}

\cos因此,和一起使用并没有什么不好的\xdef。但是当我尝试让这段代码看起来更像上面的代码时\setagenda,事情就变得有些糟糕了,我无法理解。

\documentclass{article}
\usepackage{etoolbox}
\usepackage{pgffor}
\begin{document}
\let\mytrial\relax
\foreach \x in {$\cos$,
                $x^2+x$}
  {\xdef\mytrial{\mytrial\x}}
\mytrial
\end{document}

我甚至没有收到任何错误。TeX 只是进入了一个无限循环(就好像里面有一个 LaTeX3'ish 夸克之类的东西)。

好吧,我有\let一些东西要放在\relax那里。所以我尝试了

\documentclass{article}
\usepackage{etoolbox}
\usepackage{pgffor}
\begin{document}
\def\mytrial{\relax}
%%\def\mytrial{}%%<--- this line works too!
\foreach \x in {$\cos$,
                $x^2+x$}
  {\xdef\mytrial{\mytrial\x}}
\mytrial
\end{document}

它确实有效,这让我大吃一惊!最后一个例子和我在里面做的有什么不同?里面\setagenda甚至没有任何命令来\expandonce节省以后再说。

我的理解\noexpand\x

\xdef\mycmd{\noexpand\somecmd}

结果是

\mycmd=\somecmd

我的理解\expandonce\x\x=\noexpand\cos

\xdef\mycmd{\expandonce\x}

结果是

\mycmd=\noexpand\cos

所以如果我有类似的东西

\mycmd=\noexpand\cos
\x=\noexpand\tan

然后尝试

\xdef\mycmd{\expandonce\mycmd \expandonce\x}

我期望结果是

\mycmd=\noexpand\cos \noexpand\tan

发生了什么?我不明白什么?我想我应该得出结论,环境内部发生了一些事情tabular,我还没有用我的例子挖掘出来。但我真的不确定那会是什么。

答案1

这个问题涉及的内容很多,很难一一分析。

让我们解决这个\cos问题。如果没有amsmath,它的定义是

*\show\cos
\cos:
macro:->\mathop {\operator@font cos}\nolimits

(此处以及下文中,我将输出报告为交互式会话;*是交互式会话中的提示)。 的扩展\operator@font\mathgroup\symoperators两个不可扩展的标记。如果我们尝试,我们会得到

*\xdef\x{\cos}\show\x
> \x=macro:
->\mathop {\mathgroup \symoperators cos}\nolimits .

然而,当amsmath加载时,情况就不同了:

*\RequirePackage{amsmath}
*\show\cos
\cos=macro:
->\qopname \relax o{cos}.

并且\qopname是通过 定义的,\DeclareRobustCommand所以它很可能不会存在\edef(或者\xdef只是\global\edef)。事实上我们发现

% amsopn.sty, line 49:
\DeclareRobustCommand{\qopname}[3]{%
  \mathop{#1\kern\z@\operator@font#3}%
  \csname n#2limits@\endcsname}

% amsopn.sty, line 38:
\def\nolimits@{\@ifnextchar\limits{\nolimits\@gobble}{\nolimits}}

最终,罪魁祸首是:它包含\@ifnextchar。在进行扩展定义时,应该使用\protected@xdef来克服这个问题。例如,我们会得到

*\protected@xdef\x{\cos}\show\x
> \x=macro:
->\protect \qopname  \relax o{cos}.

这并没有说明问题。

\relax问题呢?这很容易解释。当一个控制序列不可扩展时,\edef不会对它做任何事情。并且\relax不可扩展。您的代码

\let\mytrial\relax
\foreach \x in {a,b}
  {\xdef\mytrial{\mytrial\x}}

(我使用 simplyab你使用的 token 只会让事情变得更加复杂,但增加的复杂性无关紧要)相当于

\let\mytrial\relax
\xdef\mytrial{\mytrial a}
\xdef\mytrial{\mytrial b}

请注意,在处理 时\edef\cs{<balanced text>},TeX 首先通过进行扩展来计算替换文本,直到剩下不可扩展的标记为止;我们将结果称为<balanced text expanded>;只有在执行此操作后,TeX 才会执行 的等效操作\def\cs{<balanced text expanded>}。在执行最后一步时,TeX 不会以任何方式解释替换文本中的标记。

第一个 之后,的\xdef展开式为,现在不再是不可展开的了。因此第二个会尝试展开;猜猜会发生什么?它如下\mytrial\mytrial a\mytrial\xdef\mytrial

\mytrial b -> \mytrial ab -> \mytrial aab -> ...

因为\edef\xdef会“一直”进行下去,正如前面所说:它们会一直进行扩展,直到只剩下不可扩展的标记。当然,当你有 时\def\mytrial{},第一步的扩展将很简单a,不会出现无限循环。

相关内容