LaTeX3中控制宏展开的参数说明符中有x型和e型,都表示完全展开,请问两者具体的区别是啥?比如下面这两个函数:
\use:x{<可展开的记号>}
\use:n{<可展开的记号>}
二者的区别在何处?
这两个宏都需要吃掉一个参数,并且完全展开这个参数。
第一个区别是,\use:e
(在要被完全展开的上下文中)可以被完全展开(expands all tokens fully),\use:x
不能被完全展开。
比如 \use:e { <tl> }
中 <tl>
就是“要被完全展开的上下文”,如果这里面有 \use:e
,它也会被完全展开,\use:x
则不会被展开。
例如,
% protected 宏 \__my_unexp: 在要被完全展开的上下文中不会被展开,保持原样
\cs_set_protected:Npn \__my_unexp: { do~something }
\tl_set:Nn \l__my_tl { do~other }
\use:e { \__my_unexp: \use:x { \l__my_tl } }
其结果是 \__my_unexp: \use:x { do~other }
,\__my_unexp:
和 \use:x
不会被展开,括号也不会被展开,但是 \l__my_tl
会被展开,这个展开是由 \use:e
引起的,而不是 \use:x
。
而
\use:e { \__my_unexp: \use:e { \l__my_tl } }
的结果是 \__my_unexp: do~other
,\__my_unexp:
不会被展开,但是里面的 \use:e
会被展开,它需要一个参数,即 \l__my_tl
,然后这个里面的 \use:e
展开它的参数 \l__my_tl
。
有没有办法阻止记号在要被完全展开的上下文中被展开呢?有。就是 \exp_not:N
和 \exp_not:n
(及其变体)。
\use:e { \__my_unexp: \exp_not:N \use:e { \l__my_tl } }
这样,里面的那个 \use:e
就不会被展开,但 \l__my_tl
会被外面那个 \use:e
展开,结果是 \__my_unexp: \use:e { no~other }
。
而
\use:e { \__my_unexp: \exp_not:n { \use:e { \l__my_tl } } }
结果是 \__my_unexp: \use:e { \l__my_tl }
,因为 \exp_not:n
的作用是让它的参数不被展开。
以上代码把外面的那个 \use:e
换成 \use:x
,结果完全相同。
另一个区别是,\use:x
的参数中,parameter(catcode=6),比如 #
,需要双写,但 \use:e
不需要,如:
\use:x { \cs_set:Npn \exp_not:N \__foo_do:n #1 { } }
\use:e { \cs_set:Npn \exp_not:N \__foo_do:n #1 { } }
第一行会报错。需要写成 ##1
。
除此之外,它们的作用完全相同。
l3kernel 昨天(2023-05-17,版本为 Released 2023-05-15)的更新中,要求引擎必须有 \expanded
primitive 了(从 TeXLive 2019 开始 pdfTeX、XeTeX、LuaTeX 都已经有这个 primitive 了),\use:e
也是使用 \expanded
实现的。
目前,有 e
变体的应当用这个变体,使用 \cs_generate_variant:Nn
时,也应生成 e
变体。
某些宏和 primitive,比如 \tl_set:Nx
、\cs_set_nopar:Npx
,它们内部使用的 primitive 已经完成了完全展开这个操作,所以不再需要使用 e
变体来展开。(当然不全是如此)
TeX(和 LaTeX)里关于“展开”的内容可以写一篇10页以上的文章了。
非常感谢!大佬太强了,简直就是一本行走的LaTeX3百科全书!
不好意思,上面那个
\use:n
应当是\use:e
,我写错了,不过雾月大佬已经猜到了我要说啥。