\expandafter 和 \aftergroup:2n+1 和 n^2-1 规则从何而来?

\expandafter 和 \aftergroup:2n+1 和 n^2-1 规则从何而来?

TeX 基元\expandafter\aftergroup都有“经验法则”,指出

  1. \expandafter应该使用2n+1次数来提前查看n标记(这是正确的吗?)。
  2. 类似的“经验法则”也适用于\aftergroup作业:n^2-1

有人能解释一下这些规则从何而来吗?我理解将标记扩展为其定义的基本思想,但我无法将其推广到任意的前瞻,也就是说,扩展标记标记n对我来说仍然很困难。

附言:我添加了一个“aftergroup”标签,因为我不确定哪个标签最合适。如果您认为您知道如何正确标记,请随意调整。

答案1

\expandafter已在其他地方讨论过,因此我将限制于\aftergroup

考虑纯文本文件

{{{
xxx
\aftergroup a
xxx
\aftergroup\aftergroup
\aftergroup b
xxx
\aftergroup\aftergroup
\aftergroup\aftergroup
\aftergroup\aftergroup
\aftergroup c
xxx }
yyy }
zzz }

\bye

这产生了

在此处输入图片描述

\aftergroup从输入流中取出以下标记,并在组结束后重新插入。

因此在第一个之后\aftergroup a插入a}

\aftergroup为了更好地理解这三点b,请按照图示逐行考虑它们。

\aftergroup\aftergroup第一个\aftergroup执行并将(未执行的)\aftergroup令牌放在组的末尾(在这种情况下,它将被插入到a先前放置在\aftergroup队列中的令牌之后)。

\aftergroup bb位于当前组末尾的地方,它将被插入到\aftergroup刚刚讨论的之后。

这意味着首先插入}标记,然后进行排版,然后在遇到下一个标记时再次删除并重新插入。a\aftergroup ba\aftergroupb}

\aftergroup前面的七个c也类似。一开始读行时,你会发现每个其他标记都插入在当前组之后,因此插入 b标记 之后(正如刚才讨论的那样)会插入该组之后,因此最后插入 c 并进行排版。\aftergroup\aftergroup\aftergroup c\aftergroup c}

为了将令牌提升一个额外的组级别,您需要对\aftergroup前一个级别使用的所有令牌进行分组,再加\aftergroup上感兴趣的令牌,您会发现通常有 1,3,7,... 2 ^ n-1 个\aftergroup令牌来将令牌提升通过 n 个组级别。


请注意,并不是说必须有 2^n-1 个\aftergroup有趣的效果,可以通过其他分组获得:

{{{
xxx
\aftergroup\aftergroup a
yyy}zzz
\aftergroup\aftergroup\aftergroup\aftergroup b
www}qqq}mmm

\bye

生产

在此处输入图片描述

这里\aftergroup\aftergroup位于\aftergroup第一个 之后}a完全不受影响,因此在 之后按正常方式排版xxx。然后在 处插入}标记\aftergroup 并应用于第一个z,因此只有两个zz在此时排版,第一个在z之后的下一个处排版。}www

\aftergroup之前的四个b类似。两个\aftergroup标记被移除并插入到下一个标记中},并且b完全不受影响,因此在 之后排版zz。这两个标记\aftergroup被插入到下一个标记中},因此输入是

\aftergroup\aftergroup qqq}mmm

\aftergroup在之后插入一个},因此相当于

qqq}\aftergroup mmm

因此,一个m从输入中取出,两个mm被排版。第一个m只是默默地消失,因为它会出现在当前组的末尾,但这是顶层,所以它只是丢失了(不是错误)。

答案2

(不可扩展)原语\aftergroup仅适用于下一个标记;它使 TeX 将标记保存在 FIFO 列表中,该列表将在当前组结束后立即传送。所以

\begingroup\aftergroup x\aftergroup y\endgroup

和输入一样xy:列表是“先进先出”的。请注意,对于宏,TeX 只保存宏,而不保存其含义。因此

\def\foo{X}
\begingroup\def\foo{Y}\aftergroup\foo\endgroup

将打印,因为一旦执行,X的重新定义就会消失。\foo\endgroup

我们属于哪个组并不重要;它可以是十六种不同的组类型中的任何一种。例如,\hbox{A\aftergroup B}将框住一个并在框外A打印;第一个例子可能是。B{\aftergroup x\aftergroup y}

撇开由于为 FIFO 列表保留的大小有限而导致的问题,哪些标记可以跟在后面\aftergroup?任何标记,甚至{};LaTeX 环境的定义lrbox在这方面非常有启发性。

如果您想要链接标记以便在当前组结束后重新出现,只需在每个标记前面加上\aftergroup

\begingroup\aftergroup\mbox\aftergroup{\aftergroup X\aftergroup}\endgroup

\mbox{X}将使 TeX在组结束后立即看到标记(并且所有设置都恢复)。

注意\aftergroup{\mbox{X}}注意不是相当于上面的代码:\aftergroup不接受括号中的参数,它只适用于紧随其后的标记

如果你想推迟代码团体赛结束,很简单:

\begingroup\begingroup
\aftergroup\aftergroup\aftergroup\foo
\endgroup\endgroup

意思应该很清楚:当前组(嵌套级别 2)结束时,TeX 将交付\aftergroup\foo,它将保存回\fooaftergroup 列表中,以便在外层组结束后交付。任何组级别都有此列表的化身。

如果你想爬三级,只要记住每组消耗一个\aftergroup:所以

\begingroup\begingroup\begingroup
\aftergroup\aftergroup
\aftergroup\aftergroup
\aftergroup\aftergroup
\aftergroup\foo
\endgroup\endgroup\endgroup

就可以了,因为当第 3 级组结束时,列表将包含

\aftergroup\aftergroup\aftergroup\foo

通过归纳法自己证明一下,为了爬上去n级别,你需要 2n -\aftergroup之前有 1 个标记\foo

相关内容