我想知道 (La)TeX 接口定义命令时使用反斜杠的原因。我知道为什么必须使用反斜杠来调用(扩展)命令(宏),但我不明白为什么在定义中使用它。
在 (La)Tex 中,有很多种方法可以定义命令(忽略命令\let
和 LaTeX 3 核心以及可能的其他命令),命令名称以反斜杠开头:
- TeX:
\def
、\gdef
和,\edef
都xdef
可能带有前缀\long
- LaTeX :
\newcommand
,,,,都可能有后缀\renewcommand
providecommand
DeclareRobustCommand
*
- etoolbox :
\newrobustcommand
,,,都可能带有后缀\renewrobustcommand
providerobustcommand
*
- xparse:
\DeclareDocumentCommand
,,,,,所有可能在参数规范中有\NewDocumentCommand
一个\RenewDocumentCommand
\ProvideDocumentCommand
+
还可以定义没有间隙的命令
- TeX:(
\expandafter\def\csname name \endcsname
与上面提到的 TeX 命令类似) - etoolbox:(
\csdef
类似于上面提到的 TeX 命令)
我认为没有反斜杠的定义有明显的优势:
- 更通用:允许创建动态命名的命令(例如 \csdef{double#1}{#1,#1})
- 更好的语义:反斜杠意味着使用变量,即扩展它
- 更短:保存一个字符,不打扰眼睛
问题是:既然默认命令定义似乎更有用,为什么还需要反弹呢?
更详细地说明一下这个问题:显然,与 TeX 的定义相比,etoolbox 的定义具有更短、更清晰的优势。xparse 定义在参数灵活性方面也具有明显的优势。因此,将它们结合起来似乎很自然。如果定义(使用来自\expandnext
etextools)如下命令
\NewDocumentCommand{\declare}{mmm}{%
\expandnext{\DeclareDocumentCommand}{\csname #1\endcsname}{#2}{#3}%
}
一个人会失去什么?让我们假设,new
和renew
将provide
被类似地定义,让我们将局部/全局讨论和第三个论点的可能扩展放在一边,\gdeclare
从长远来看,导致\edeclare
和。xdeclare
答案1
有几个原因可以解释为什么定义文档命令总是使用命令的控制序列 ( \foo
) 而不是控制序列名称 ( foo
)。当然,其中一些归结为“你必须问 Leslie Lamport 或 Don Knuth”,因为它遵循 TeX 基础知识。(例如,\newcommand\foo
镜子\def\foo
和\DeclareDocumentCommand\foo
镜子\cs_new:Npn \foo
。)
首先,要求定义时的‘外观’与使用时的‘外观’相同,具有内在的一致性。
其次,要求 token 是构造函数可以避免对命令名称中通常出现的内容产生混淆。例如,如果你这样做
\declare{foo-bar}...
\foo-bar
后者不起作用(假设标准 LaTeX 类别代码),因为 TeX 会“看到”标记\foo
后跟连字符和字母b
,a
和r
。这看起来是个有问题的好办法。
第三,目前的设置允许“专家”跳过{
...}
对
\newcommand\foo{definition}
工作原理与
\newcommand{\foo}{definition}
当 TeX 比较“小”时,这一点很重要(我们在那里保存了两个标记),但许多人也发现它更容易阅读。(此外,由于大多数优秀的编辑器对 LaTeX 标记的突出显示方式与“运行文本”不同,因此使用基于标记的方法对许多编辑器来说效果更好。)
与此相关,你必须记住,当前的界面是在 20 世纪 80 年代基于 20 世纪 70 年代末开发的系统设计的。在\csname
过去,对标记(单独的字母而不是控制序列)的扩展和存储的额外工作比现在重要得多。
最后,如果你看一下我们想要的 LaTeX3 内容避免在文档界面级别尽可能使用“动态”定义。LaTeX2.09/LaTeX2e 的一个教训是,明确定义的界面是一件好事:鼓励使用动态名称对此没有帮助。
答案2
你可以自由地定义,更简单地说,
\def\NewDocumentCommandName#1{%
\expandafter\NewDocumentCommand\csname #1\endcsname}
然后说
\NewDocumentCommandName{foo}{mm}{Whatever with #1 and #2}
如果你愿意的话。但这并不比
\NewDocumentCommand{\foo}{mm}{Whatever with #1 and #2}
我没有看到“动态定义命令”的清晰语法。
Unix shell 中保留了变量“定义”和“使用”之间的区别,其中foo=bar
赋值并$foo
传递值。这样做是有原因的。在我看来,TeX 不是这样,就像在许多其他编程语言中一样。