我正在尝试使用 LaTeX3 的映射命令之一,\tl_map_variable:nNn
如下所示:
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\tl_new:N \l_foo_tl
\tl_set:Nn \l_foo_tl {x}
\tl_use:N \l_foo_tl
\tl_map_variable:nNn {abc} \l_foo_tl {\tl_use:N \l_foo_tl}
\tl_use:N \l_foo_tl
\ExplSyntaxOff
\end{document}
预期输出是xabcx
。但是,map 函数似乎陷入了无限循环,我不确定为什么会发生这种情况。即使将标记列表更改{abc}
为{}
也会产生相同的结果。
通过启用日志文件中的宏跟踪,我可以发现问题与\q_recursion_tail
一遍又一遍地扩展为自身有关。
有人能解释一下这里出了什么问题吗?
答案1
编辑(由BLF):现在已经修复了这个问题:\tl_map_variable:nNn
相关函数让变量等于标记列表中的最后一项,而不是尾随标记。
\tl_map_variable:nNn
不创建组级别,因此代码末尾\l_foo_tl
包含列表中的最后一个标记,即\q_recursion_tail
(插入到您的后面abc
以检测列表的末尾)。然后,当您执行时,\tl_use:N \l_foo_tl
您会展开\q_recursion_tail
,从而导致无限递归。
\tl_map_variable:nNn
展开一次为:
\__tl_map_variable:Nnn #2 {#3} #1 \q_recursion_tail
\prg_break_point:Nn \tl_map_break: { }
首先要做\__tl_map_variable:Nnn
的是将 中的第一个项#1
(最终为\q_recursion_tail
)分配给#2
,即⟨tl var⟩
。您应该使用另一个⟨tl var⟩
来避免这种情况:
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\tl_new:N \l_foo_tl
\tl_new:N \l_bar_tl
\tl_set:Nn \l_foo_tl {x}
\tl_use:N \l_foo_tl
\tl_map_variable:nNn {abc} \l_bar_tl { \tl_use:N \l_bar_tl }
\tl_use:N \l_foo_tl
\ExplSyntaxOff
\end{document}
文档中没有提到(至少我找不到),⟨tl var⟩
结束后的内容和可用性\tl_map_variable:nNn
,所以我不知道这是否是设计使然。
但是,您可以定义一个版本,在函数结束时\tl_map_variable:nNn
保存值并恢复它:⟨tl var⟩
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_protected:Npn \siracusa_tl_map_variable:nNn #1#2
{
\exp_args:NV
\__siracusa_tl_map_variable:nnNn #2 {#1} #2
}
\cs_new_protected:Npn \__siracusa_tl_map_variable:nnNn #1#2#3#4
{
\tl_map_variable:nNn {#2} #3 {#4}
\tl_set:Nx #3 { \exp_not:n {#1} }
}
\ExplSyntaxOff
\begin{document}
\ExplSyntaxOn
\tl_new:N \l_foo_tl
\tl_set:Nn \l_foo_tl {x}
\tl_use:N \l_foo_tl
\siracusa_tl_map_variable:nNn {abc} \l_foo_tl { \tl_use:N \l_foo_tl }
\tl_use:N \l_foo_tl
\ExplSyntaxOff
\end{document}