为什么 \dimexpr 会吞掉 \relax?

为什么 \dimexpr 会吞掉 \relax?

遵循以下评论在 LaTeX 源代码中使用距离值进行数学运算

+1 教我\dimexpr可以选择吞掉\relax。昨天我尝试使用 来\relax作为 的分隔符\numexpr,但我不明白为什么\relax消失了,尽管它不可​​扩展。– Hendrik Vogt 2 月 18 日 9:32

@Hendrik:是的,我认为你需要两个\relax。我发现\relax吞咽非常有用。它的朋友也喜欢\numexpr这样做。 – Martin Scharrer♦ 2 月 18 日 9:36

这个问题在 Joseph 和 Martin 的回答中再次被提及维度还是宏观,哪个更好?,我问自己为什么 Etex 会这样做?我发现它不直观,我不明白它如何有助于避免执行无操作命令。

答案1

除了亨德里克所说的,我认为总体观点是\numexpr\dimexprETC。可以在完全扩展上下文中使用,不会留下任何残缺\relax或空格:

\edef\example{\the\dimexpr 10 pt + 20 pt \relax}

给出\example定义为,30pt没有意外标记。这在很多方面都比保留原位的替代方案“简洁”得多\relax。同样的论点不适用于 TeX 的寄存器设置,因为它永远不可扩展,所以不会出现问题。

(当然,要得到明确的答案,您需要询问实际编写此代码的 NTS 团队成员。)

答案2

我想说,这使得\dimexpr以完全可扩展的方式划分 a 变得很容易。放置 a\relax是划分 TeX 维度的常用方法,这是我通过痛苦经历学到的\relax:在之类的后面加上 a 总是一个好主意\hskip1pt。现在看来 eTeX 只是从中得出了一个原则。

(另一种方法是空间来界定 TeX 维度,但首先,空格\relax更明显,其次,有时不太容易添加空格,即在控制序列之后。正如 Bruno 在他的评论中指出的那样,空格不能用于划分\dimexpr和朋友。)

答案3

原因与 TeX 吞掉数字末尾的空格相同。在 TeX 的情况下,这是为了干净地停止数字,并确保在所有情况下它都会终止,而不会进一步扩展任何内容或插入空格。事实上,TeX 可能出于同样的原因跳过控制字(多字母控制序列)后的空格(尽管这发生在不同的处理阶段)。这个想法是应该始终能够“停止而不插入任何内容”。

示例:\ifdigit下面测试参数是否为数字。后面的空格#1是为了防止 TeX\expandafter过早扩展第一个数字。另一方面,我们不希望空格出现在输出中。所以至少在这种情况下,TeX 的空格吞噬是一个功能。

\long\def\ifdigit#1{%
    \ifnum 9<1\string #1 %
        \expandafter\@firstoftwo
    \else
        \expandafter\@secondoftwo
    \fi}

eTeX 的设计者可以决定用空格来停止\numexpr或,因为他们只是使用 TeX 的程序来读取操作数。这些程序已经删除了尾随空格。eTeX 看不到之前\dimexpr的空格。从技术上讲,可以用+\numexpr 1 + 2\numexpr连续使用空格标记,并吞噬它们,但这将非常难以输入,因为连续两个空格字符相当于一个。必须选择其他分隔符。它必须是不可扩展的,最好是语言中已经存在的,并且在某种情况之外使用时最好什么也不做\...expr……无需添加新的原语:\relax是一个自然的选择。

现在考虑\compareint如下定义的函数

\long\def\compareint#1#2#3{%
    \ifnum\numexpr#1\relax#2\numexpr#3\relax
        \expandafter\@firstoftwo
    \else
        \expandafter\@secondoftwo
    \fi}
\compareint{1+2}<{3-1}{Yes}{No}

在这个特殊情况下,遗留\relax不会成为问题。但是,想想嵌套这个:

\def\X{345}\def\Y{534}
\compareint {132} < {\compareint{12}>{9}{\X}{\Y}+1} {Yes} {No}

如果\relax不从内部移除,它会过早地\compareint停止外部的扩展(实际上,在扩展到或之前,所以这将是一个问题)。\compareint\X\Y

答案4

实际上,e-TeX 手册中的文档已经用一个说明性的例子回答了这个问题,令人惊讶的是,这里的答案中没有提到这个例子。那里给出的例子是:

\ifdim\dimexpr (2pt-5pt)*\numexpr 3-3*13/5\relax + 34pt/2<\wd20

相当于\ifdim 32pt < \wd20。在这种情况下,内部\numexpr 3-3*13/5\relax扩展为-5(注意舍入),因此外部\dimexpr变得相当于(-3pt) * (-5) + 17pt。如果\relax没有吞掉 ,而是留在输入流中,那么外部\dimexpr也会在 处终止\relax,从而导致错误。


为了完整起见,复制语法文档此处,稍微重新格式化:

e-TeX 引入了数字、dimen、glue 或 muglue 类型的表达式概念,可用于需要该类型数量时。此类表达式由 e-TeX 的扫描机制进行评估;

  • 他们是发起通过命令\numexpr\dimexpr\glueexpr或之一\muexpr(确定类型)以及可选的终止一个\relax(将被扫描机制吸收)

  • 一个表达:由一个或多个要加或减的相同类型的项组成;

  • A学期类型:由一个因素该类型,可选地乘以和/或除以数字因素; 最后

  • A因素类型: 是括号内的子表达式,或者是该类型的数量(数字等)。

因此,条件

\ifdim\dimexpr (2pt-5pt)*\numexpr 3-3*13/5\relax + 34pt/2<\wd20

当且仅当盒子 20 的宽度超过 时才为真32 pt

注意使用\relax来终止内部(数字)表达式,外部(dimen)表达式会由<不适合表达式语法的标记 ₁₂ 自动终止。

然后还有几段关于算术(例如四舍五入)及其扩展的段落。

相关内容