在 expl3 中,是否有一种“好”的方法可以在组之外进行“本地”更改?

在 expl3 中,是否有一种“好”的方法可以在组之外进行“本地”更改?

我有以下功能:

\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
 }

相关内容