这个问题只是为了我自己理解扩展是如何工作的。
我在文档中使用 siunitx 包。为了确保与自己保持一致,我尝试将测量结果写成宏,这样就可以从一个地方全局更改它们。
我注意到,在其中一个宏的末尾添加一对括号{}
会导致 siunitx 出错。看看以下 MWE:
\documentclass{article}
\usepackage{siunitx}
\begin{document}
\newcommand{\aMeasurement}{0.9(1)}
% This works fine
The answer was \num{\aMeasurement}.
% This gives an error
The answer was \num{\aMeasurement{}}.
\end{document}
我以为宏的参数在运行之前就已经完全展开了。如果是这样,怎么可能siunitx
分辨出这两个调用之间的区别呢?
答案1
忽略具体细节,siunitx
似乎对 TeX 的执行顺序存在一些误解。
首先,宏参数在宏调用之前不会扩展,只有在宏扩展后满足参数时才会扩展(如果有的话)。
您可以在
\def\foo#1{}
\foo{\somethingundefined}
\bye
\somethingundefined
在调用之前不会扩展\foo
(这会产生错误)事实上,由于\foo
没有使用#1
参数,所以根本不会扩展。
其次{}
,宏不是参数,除非宏被定义为接受参数(\aMeasurement
你问题中的宏不接受参数)
后
\def\foo{hbox}
\foo
\foo{}
\foo
和\foo{}
根本不等价,\foo
扩展为hbox
和\foo{}
扩展为hbox{}
这些将采用非常不同的代码路径,例如
\csname\foo\endcsname
将执行命令\hbox
,但
\csname\foo{}\endcsname
将执行名称为的命令hbox{}
(该名称之前未定义,其行为类似于\relax
)
答案2
您可能被这样的事实误导了:当在文本中使用无参数宏时,它后面应该跟一些使得 LaTeX 尊重其后空格的内容:
\LaTeX has macros
不会在徽标和“has”之间打印空格,而
\LaTeX{} has macros
打印正确。然而,这对空括号不是作为宏扩展的一部分被吞噬,因为 TeX 知道\LaTeX
没有参数,所以它不会寻找参数。
如果定义宏如下,情况会有所不同
\newcommand{\foo}[1]{vim}
(未使用该参数)和
\vim{} can't be escaped from
确实会吞掉括号。例如,\edef\VIM{\foo{}}
相当于\def\VIM{vim}
,因为括号作为参数替换的一部分消失。另一方面,
\vim\ can't be escaped from
将打印不“vim” 和 “can't” 之间的空格,因为参数现在是“控制空间”,而宏会丢弃其参数。
您的输入\num{\aMeasurement{}}
基本上相当于
\num{0.9(1){}}
并且您会收到错误消息
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! siunitx error: "invalid-token-in-number"
!
! Invalid token '\q_recursion_tail ' in numerical input.
!
! See the siunitx documentation for further information.
!
! For immediate help type H <return>.
!...............................................
所指的无效标记是左括号{
。如果你滚动浏览错误,你会看到
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! siunitx error: "invalid-number"
!
! Invalid numerical input '0.9(1){}'.
!
! See the siunitx documentation for further information.
!
! For immediate help type H <return>.
!...............................................
这应该足够清楚了:\SI doesn't like at all the tokens
{}`。