将全局变量的当前值放入 prop 列表中

将全局变量的当前值放入 prop 列表中

这或多或少是直接跟进这个问题

问题在于将全局变量的当前值放入 LaTeX3 prop 列表中。诀窍是使用变V体来获取价值而不是记录变量名对应的token列表。

现在问题是相同的,只不过我需要的是变量的值,而不是计算的输出。我尝试在以下 MWE 中的各个地方使用Vs 和xs,但我无法得到正确的东西。

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\int_new:N \g_seamus_foo_int
\int_new:N \l_seamus_tmpa_int

\cs_new:Npn \seamus_set_int #1 {
  \int_set:Nn \g_seamus_foo_int {#1}
}

\cs_new:Npn \seamus_modify_int #1 {
  \int_set:Nn \l_seamus_tmpa_int {
    \int_mod:nn {\g_seamus_foo_int + #1}{60}
  }
  \int_gset_eq:NN \g_seamus_foo_int \l_seamus_tmpa_int
}

\cs_new:Npn \seamus_return_int #1 {
  \int_compare:nNnTF {\g_seamus_foo_int} > {#1} {Big (\int_eval:n{\g_seamus_foo_int})} {Small (\int_eval:n{\g_seamus_foo_int})}
}

\prop_new:N \g_seamus_prop_list

\cs_new:Npn \seamus_set_value #1#2 {
  \prop_gput:NnV \g_seamus_prop_list {#1}{#2}
}

\cs_new:Npn \seamus_get_value #1 {
  \prop_get:Nn \g_seamus_prop_list {#1}
}

\NewDocumentCommand\Marker{m}{
  \seamus_set_value{#1}{
    \seamus_return_int{30}
  }
}

\NewDocumentCommand\ReturnMark{m}{
  #1: \seamus_get_value{#1}
}
\NewDocumentCommand\SetNumber {m} {
  \seamus_set_int{#1}
}

\NewDocumentCommand\ChangeNumber{m}{
  \seamus_modify_int{#1}
}

\NewDocumentCommand\PrintNumber{}{
  \seamus_return_int{30}
}
\ExplSyntaxOff
\begin{document}
Set at 12: \SetNumber{12}\PrintNumber\\
Add 7: \ChangeNumber{7}\PrintNumber\ (Marker foo) \Marker{foo}\\
Add 12: \ChangeNumber{12}\PrintNumber (Marker bar) \Marker{bar}\\
Add 30: \ChangeNumber{30}\PrintNumber\\
\ReturnMark{foo}\\
\ReturnMark{bar}

\end{document}

这是我能做的最简单的例子。实际用例更加复杂。主要思想是命令应该将prop 列表中输出\Marker{foo}的当前值保存为键。因此,所需的输出是bar` 应该是“bar: Big (31)”。\seamus_return_int\g_seamus_prop_listfoo\ReturnMark{foo} should give "foo: Small (19)" and

但是,\ReturnMark似乎使用调用时的值,而不是被调用\g_seamus_foo_int时保存的值。\Marker

我确信有一些我不理解的扩展……

答案1

在我看来,x当你将值存储在属性列表中时,你想对其进行类型扩展。添加正确的参数规范、需要它的函数的受保护状态、删除一些不必要的代码并修复全局状态会导致类似

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\int_new:N \g_seamus_foo_int
\prop_new:N \g_seamus_prop

\cs_new:Npn \seamus_gset_int:n #1
  {
    \int_gset:Nn \g_seamus_foo_int {#1}
  }

\cs_new:Npn \seamus_gmodify_int:n #1
  {
    \int_gset:Nn \g_seamus_foo_int 
      {
        \int_mod:nn { \g_seamus_foo_int + #1 } { 60 }
      }
  }

\cs_new:Npn \seamus_return_int:n #1
  {
    \int_compare:nNnTF \g_seamus_foo_int > {#1}
      { Big~( \int_use:N \g_seamus_foo_int ) }
      { Small~( \int_use:N \g_seamus_foo_int ) }
  }
\cs_new_protected:Npn \seamus_set_value:nn #1#2
  { \prop_gput:Nnn \g_seamus_prop {#1} {#2} }
\cs_generate_variant:Nn \seamus_set_value:nn { nx }

\cs_new:Npn \seamus_get_value:n #1
  { \prop_get:Nn \g_seamus_prop {#1} }

\NewDocumentCommand \Marker { m }
  {
    \seamus_set_value:nx {#1}
      { \seamus_return_int:n { 30 } }
  }

\NewDocumentCommand \ReturnMark { m }
  { #1: \seamus_get_value:n {#1} }
\NewDocumentCommand \SetNumber { m }
  { \seamus_gset_int:n {#1} }

\NewDocumentCommand\ChangeNumber { m }
  { \seamus_gmodify_int:n {#1} }

\NewDocumentCommand\PrintNumber { } 
  { \seamus_return_int:n { 30 } }
\ExplSyntaxOff
\begin{document}
Set at 12: \SetNumber{12}\PrintNumber\\
Add 7: \ChangeNumber{7}\PrintNumber\ (Marker foo) \Marker{foo}\\
Add 12: \ChangeNumber{12}\PrintNumber (Marker bar) \Marker{bar}\\
Add 30: \ChangeNumber{30}\PrintNumber\\
\ReturnMark{foo}\\
\ReturnMark{bar}
\ExplSyntaxOn
\prop_show:N \g_seamus_prop
\ExplSyntaxOff

\end{document}

一般来说,如果你想要强制一个条目具有某种“结果”,你很可能正在寻找x-type 扩展。为此,你当然需要确保底层代码是可扩展的。


函数\cs_generate_variant:Nn通常用于expl3编程以控制扩展。对于函数\foo:n,参数按原样使用,例如在存储的情况下,这意味着在

\int_set:Nn \l_tmpa_int { 10 }
\tl_set:Nn \l_tmpa_tl { \int_use:N \l_tmpa_int }

标记列表包含文字\int_use:N \l_tmpa_int而不是计数器的值(10)。

通过创建变体,我们可以定义参数在传递给基函数之前如何扩展。因此

\cs_generate_variant:Nn \tl_set:Nn { Nx }

允许

\tl_set:Nx \l_tmpa_tl { \int_use:N \l_tmpa_int }

现在,在应用x基函数之前,参数首先经过-type 扩展。(注意:将保持现有变体不变,因此对于手动调整的变体(例如!)而言是“安全的”。)\tl_set:Nn\cs_generate_variant:Nn\tl_set:nx

作为编程的一般原则expl3,除非执行低级工作(例如使用分隔参数),否则通常应该使用变体而不是“硬编码”方法扩展参数。


中的函数(宏)的可扩展性expl3通常应定义明确。完全可扩展的函数应使用\cs_new:Npn或类似方法进行定义,而那些不可扩展的函数应使用 创建\cs_new_protected:Npnexpl3文档指出了哪些函数是可扩展的:如果您创建一个新函数,并且它仅有的使用可扩展功能那么它本身也是可扩展的,否则就不可扩展。

采用这种方法的原因是,这意味着在如下结构中

\tl_set:Nx \l_tmpa_tl {  \foo:n { arg } }

任何一个

  1. \foo:n将可扩展并正常工作以给出“结果”
  2. \foo:n将受到保护,因此不会因x-type 扩展而改变

使用 LaTeX2e 的经验表明,宏存在“意外”部分扩展的问题。(请注意,ConTeXt 采取了类似的全有或全无方法。)

相关内容