1.
你的理解是对的,定义函数时遵循这个规则可以在需要展开其参数时不至于有太大的开销。
如果需要展开 nofe
参数之后的参数,如 \foo:Nno
、\foo:Nne
、\foo:Nff
、\foo:NnV
、\foo:no
,只有使用 \expanded
primitive(\tex_expanded:D
)才是最快的。而所谓的“optimized function”则总可以找到一个不用 \expanded
实现且比 \expanded
快的方法。(“最快”与“更快”都是从一般的情况来说的)
就是说,使用 \expanded
实现的函数都认为是需要更慢的处理。
在终端中执行 latexdef -b \ExplSyntaxOn -a \ExplSyntaxOff \exp_args:NVo
可以查看 \exp_args:NVo
的定义,(目前)它是用 \expanded
实现的,但可以找到一个不用 \expanded
(且比它快)的实现:
\cs_gset:Npn \exp_args:NVo #1#2#3
{
\exp_after:wN #1
\exp_after:wN { \exp:w \exp_after:wN
\__exp_eval_register:N \exp_after:wN #2 \exp_after:wN }
\exp_after:wN { #3 }
}
\exp_args:NNVV
和 \exp_args:NcVV
也是如此。但由于它们目前都是使用 \expanded
实现的,因此才把它们归类到需要更慢的处理的函数上。
2.last_unbraced
就是最后一个参数展开的结果的最外层不自动添加 {}
。比如
\tl_set:Nn \foo { ab }
\exp_args:No \faa { \foo } % 结果是 \faa { ab }
\exp_last_unbraced:No \faa { \foo } % 结果是 \faa ab
如果展开的结果中有括号,也不会移除括号。另外,N
和 c
参数的结果总是不自动添加 {}
。
3.
这些是用来定义 \exp_args:...
和 \exp_last_unbraced:...
的。已经明确表示应当仅用于 l3expan
这个模块中,当然想在其它地方用也不是不可以。\:::
作为分割符,前面的是展开方式,后面的是参数。
比如 \::n \::f \::o \::e \::e_unbraced \:::
就是 \:::
后面的那一项移除可能的括号,接着对随后的那些项依次进行指定的展开。(\.._unbraced
只能是最后一个)
好处是不受 TeX 的函数最多 9 个参数的限制,坏处是甚至可能比 \expanded
更慢。
问 l3中宏展开控制模块(l3expan)中对几个函数的疑惑