我开始欣赏 Latex3 expl 库,因为它提供了很好的抽象(例如字符串、列表……),但我也想创建一个尽可能高效的代码,因为它通常是我的瓶颈。在实践中,我经常混合使用遗留代码和 expl 代码,就像\def\mymacro
和\ifdefined\mymacro
而不是\cs_set:Nn \mymacro: {}
和\cs_exist:NTF \mymacro:
……所以我的问题如下:
总体而言,遗留代码是否比 expl 函数更高效?两者之间的差异有多大?例如,使用 是否\def
比 更快\cs_set
?我预计 expl 代码总是更慢,因为我预计它会首先扩展到遗留代码,但我可能错了。
举一个更具体的例子,wipet 提供了此代码,而我会自然地尝试使用标记列表和\tl_map_inline
一些检查自己实现它,例如\if_cs_exist:w
...他还重新创建了使用列表的概念,\addto
而我会使用\seq
(根据我的经验,构建起来效率很低,但也许我使用得不好?)...是否有可能在 LaTeX3 中创建同样高效的代码,还是应该坚持使用必须高效的部分的遗留代码?
更一般地说,我可以从 LaTeX3 中有效使用哪些结构?
混合使用旧代码和 expl3 代码可以吗?
答案1
任何抽象都会增加操作所需的时间。但是,绝对最大速度、代码灵活性和清晰度之间始终存在平衡。例如,expl3
(例如)中的高级条件设置为可以处理两个分支中的任意材料。与(\tl_if_eq:NNTF
相比,这对性能的影响不为零\if_meaning:w
\ifx
。但是,它是非常团队很少会担心这一点,即使是在相对低级的代码中。唯一使用“仅重命名原语”的地方是
- 早期设置中 (
l3basics
) - 在
l3regex
- 在
l3fp
对于l3fp
和l3regex
,需要团结起来“推动”TeX 意味着我们需要使用我们能用到的所有技巧。然而,这几乎不适用于其他任何地方。如果你想要一个极端的例子,数据类型在幕后tl
使用:这比但允许标记慢得非常非常慢,而且它对现实世界的影响很小,我们更喜欢一致性而不是性能。\edef\<name>{\unexpanded{<content>}
\def\<name>{<content>}
#
作为更多“用户级”代码的示例,siunitx
我并不太担心expl3
在它们有用时使用更高级别的构造。我担心的是数据结构的性质。如果您查看 v3 代码,我使用prop
用于收集单元:这些是具有多个部分的开放式列表,这种灵活的数据结构很有意义。但是,对于数字,我使用自定义方法:在内有固定数量的括号组tl
。这在那里是有意义的,因为我可以进行“经典”参数数字操作来提取和添加材料。
还值得记住的是,我们在这里比较的是expl3
经过数十年努力的代码(无论是团队直接编写的还是结合了 TeX 世界中的想法的)与您编写的原始代码。我自己的经验是,这expl3
比我做过的随意编写的代码要好。在siunitx
,v1 是慢点比 v2 更简单,尽管 v2 是内置的expl3
,而 v1 没有:全部由我手工编码。现在,我可以(今天)利用所有经验expl3
,自己编写每个循环、数据结构等,我使用:我考虑过这一点,这真是太麻烦了。