这个问题有两个方面。不幸的是,一方面是固执己见,即需要关闭投票,所以我把这部分放在最后,希望没人注意到……另一方面(首先)是严肃的 interface3 问题,我希望看到答案。
interface3.pdf 文档承诺,它将在 TeXhacker 注释中为每个命令写出它们接近哪个 latex2 命令或 TeX 基元。但它没有在任何地方包含\gdef
或\global\def
。
- 确实是
\cs_gset:Npn
像\long\global\def
? - 就
\cs_set_protected:Npn
好像\protected\long\def
?
据我所知,latex3 还旨在将“TeX 编程语言”转变为更合理的环境,即更难意外产生错误的环境。实现此目的的一种方法是使用显式而不是隐式,尤其是在危险的情况下。考虑到这一点:
\cs_new:Npn
[存在的] 是否更有可能是[\cs_gnew:Npn
我的发明],即全球性的?\cs_set:Npn
[存在的] 是否类似于[\cs_lset:Npn
我的发明],即本地的?- [
\cs_lnew:Npn
我的发明]被认为没有用,所以被放弃了,对吗? 不合格函数(无 l、无 g)有时表示局部,有时表示全局(set 与 new),这合理吗?→ 令人困惑 → 错误
\long
现在是隐式的,因为这是大多数程序员所期望的,尤其是使用 latex3 语法。对吗?- 现在调用了 Non-long
..._nopar:...
。这是意料之外的,所以它有一个明确的标签,与 TeX 最初的标签相反。对吗? - 为什么
\protected
不能基于同样的理由而隐含?即\cs_new_protected:Npn
[存在的]应该被称为\cs_gnew:Npn
[我的发明],而\cs_gnew_unprotected:Npn
[我的发明]可以是当前的\cs_new:Npn
[存在的]。
答案1
我看到Marcel 已经报道过 (1) 和 (2):我会尽力解决其他问题。
在 中,尽可能将“变量”和“函数”视为相同expl3
。但是,有些地方会稍微棘手一些。其中一个地方是,\g_...
在每个函数名称中都使用 会很麻烦:与变量不同,很少有函数被重复设置。因此,保存堆栈累积等风险很低。
所有“新”函数在创建其参数时都以全局方式起作用;对于变量,它们也在全局范围内初始化。对于函数,没有“初始”值,因此\cs_new:Npn
和类似的在全局范围内设置:相当于\global\long\def
。在指示范围的地方,这总是使用g...
和...
名称,所以没有lset
,它只是“设置”。
这创建局部函数/变量的用法以前也出现过,通常是在变量的上下文中。有人尝试过,但似乎与 TeX 的分组模型不太相符,所以没有保留。这又用了“new”而不是“gnew”:变量是总是声明,这是总是全球的。
至于“new”是否是全局的并且不需要“gnew”,我留给其他人去判断:我觉得有一套明确的“始终全局”的操作是可以的。
除非在代码级别另有标记,否则所有内容都是“长”。通常,Knuth 的\long
标记在文档中很有用,但在代码中却有问题。标记的现状是由于语言的发展:事物最初更接近 TeX 命名(例如,\def_new:Npn
而不是\cs_new_nopar:Npn
)。由于“长”状态是默认状态,因此更容易使“nopar”标记显式化。
受保护状态的平衡更为复杂:无论采取哪种方式,都会有大量的“其他情况”。同时,语言开发早在需要 e-TeX 之前就开始了。因此,在最初的想法形成之后,才添加了受保护状态。团队已经讨论过这个问题(以及函数名称不表示扩展行为的事实),但在这个阶段,改变这里实在是太晚了。
答案2
- 确实是
\cs_gset:Npn
像\long\global\def
?
\cs_gset:Npn
定义为\tex_long:D \tex_gdef:D
,因此它与 完全相同\long\gdef
。
- 就
\cs_set_protected:Npn
好像\protected\long\def
?
\cs_set_protected:Npn
定义为\tex_protected:D \tex_long:D \tex_def:D
,所以它与完全相同\protected\long\def
。
(请参阅texdoc source3
第 5.3 节“定义函数”以供参考)
答案3
每个<module>_new<...>
功能全球定义一个函数或变量,将其设置为合理的值。如果你这样做
\cs_new:Npn #1 \siemer_foo:n { whatever #1 }
,该函数是全局定义的,其动作将按照定义进行。\tl_new:N \l_siemer_foo_tl
,token列表变量全局定义,并初始化为空。\int_new:N \g_siemer_foo_int
,整型变量全局定义,初始化为0。
\g_...
对于变量来说和有什么区别\l_...
?前者类型应始终全局设置,后者局部设置。如果您这样做,TeX 不会引发错误\int_set:Nn \g_siemer_foo_int { 42 }
,但西班牙宗教裁判所可能会开始追捕您,expl3
因为概念上是错误的。实际上,如果使用以下选项加载,则会引发错误check-declarations
:
! LaTeX3 Error: Inconsistent local/global assignment
For immediate help type H <return>.
...
l.8 \int_set:Nn \g_siemer_foo_int { 42 }
这种检查计算量很大,因此只应在编写和测试代码时使用,而不是在标准文档上运行 LaTeX 时使用。
结果是没有“局部变量”的概念,即变量只能在本地使用。由于 TeX 没有“命名空间”的概念,因此最好使用描述性变量名,以确保它们的用法。与仅在本地声明变量\<module>_gnew<...>
相比,不提供\<module>_new<...>
变量名是一个明智的选择。
然而,能具有局部函数,这些函数仅在其定义的组中可用。这就是函数系列的用途\cs_set
。
\cs_new
那么和之间有什么区别呢\cs_gset
? 一个很大的区别:前者函数系列检查要定义的函数是否不存在;后者只是在没有警告的情况下覆盖定义。
因此, 是不正确的\cs_new:Npn
:\long\global\def
它是“检查函数是否存在,如果存在则抛出错误,否则执行 ” \long\global\def
。另一方面,\cs_gset:Npn
是\long\global\def
。
函数不必如此\protected
:如果是,那么其中一些函数将停止工作。举一个简单的例子,\int_eval:n
一定不是\protected
,因为它的工作是在扩展上下文中提供十进制表示的整数。