我有以下功能:
\cs_new_protected:Nn \termmenu_prompt:NN
{
\__termmenu_write_out:N #1
\group_begin:
\ior_get_str:NN \c_term_ior \choice
\tl_gset_eq:NN #2 \choice
\group_end:
}
该函数旨在提示用户进行菜单选择(其中菜单在中给出#1
),然后在本地设置#2
为该值。我现在已全局设置 tl,但出于其他原因,我想将其缩减一点。
我创建组的原因就是为了使用用户友好的\choice
令牌来提示。 #1
可能是一个真正令人讨厌的 csname,当然不是你想向最终用户显示的东西。 因此,为了安全地使用\choice
,我正在创建一个组。 诀窍是获取此信息外部該群組。
答案1
与许多其他编程语言相比,TeX 的独特之处在于我们可以安排将值从一个分组级别“偷运”出来。在函数式/过程式语言中,分组的工作方式不同,最接近的等效想法是从函数返回一个值(TeX 实际上无法做到这一点)。毕竟,它expl3
只是 TeX 的一个包装器,我们能做的事情仅限于 TeX 级别上有意义的事情。
如果您乐意使用全局变量(就像在函数式语言中当值不是返回值时所做的那样),那么建议的方法哟是完全合适的。另一方面,如果你想确保你处理的值只逃过一个组,那么你需要做的就是“偷运”出来。expl3
我们可以使用扩展控制函数之一来实现这一点
\cs_new_protected:Npn \termmenu_prompt:NN #1#2
{
\__termmenu_write_out:N #1
\group_begin:
\ior_get_str:NN \c_term_ior \choice
\exp_args:NNNV \group_end:
\tl_set:Nn #1 \choice
}
这里的想法是,我们将 的值提取\choice
到输入流中,然后用它来设置(此处)标记列表#2
。通过使用\exp_args:NNNV
一切都保持相当清晰。
将值从组中偷运出来是一种相当低级的操作,因此依赖于 TeX 的扩展概念。很难提出一种更好的语法(专用函数)来实现相同的结果但更清晰。要么将\group_end:
被隐藏,要么假定函数必须相对于 精确定位\group_end:
。一种可能的方法
\input expl3-generic\relax
\ExplSyntaxOn
\cs_new_protected:Npn \tl_set_after_group:Nn #1#2#3 \group_end:
{
#3
\group_end:
\tl_set:Nn #1 {#2}
}
\cs_generate_variant:Nn \tl_set_after_group:Nn { NV }
\group_begin:
\tl_set:Nn \l_tmpa_tl { foo }
\tl_set_after_group:NV \l_tmpa_tl \l_tmpa_tl
\tl_set:Nn \l_tmpa_tl { bar }
\tl_show:N \l_tmpa_tl
\group_end:
\tl_show:N \l_tmpa_tl
如果这样做,我们需要为每种变量类型提供一个专用函数(可能没有gset
版本!)。然后可以进行一些通用设置(\group_set_after:nNn { tl } \l_tmpa_tl { foo }
),但这似乎更尴尬。如果确实需要这种类型的功能,请在 LaTeX-L 上提出!(这里一个明显的问题是代码依赖于\group_end:
出现在以下标记中。)
答案2
您的意思是像这样,使用临时全局变量退出群组?我不太确定您实际上是否需要群组,但也许只是因为它是 MWE。
\tl_gnew:N \g_termmenu_temp_tl
\cs_new_protected:Nn \termmenu_prompt:NN
{
\__termmenu_write_out:N #1
\group_begin:
\ior_get_str:NN \c_term_ior \choice
\tl_gset_eq:NN \g_termmenu_temp_tl \choice
\group_end:
\tl_set_eq:NN #2 \g_termmenu_temp_tl
}