`\cs_new_protected` 和 `\cs_generate_variant` 起什么作用?

`\cs_new_protected` 和 `\cs_generate_variant` 起什么作用?

在我提出问题之后向现有 \ExplSyntaxOn 代码添加新参数时未定义控制序列,我试图完全理解其背后的代码。到目前为止,一切顺利,有:

  1. expl3封装和LATEX3编程
  2. https://www.texdev.net/2010/05/23/from-newcommand-to-newdocumentcommand/
  3. 在 \NewDocumentCommand 中使用键值
  4. 总是使用 \NewDocumentCommand 而不是 \newcommand?

我找到了很多解释,除了一个。这个\cs_new_protected:Npn命令的参数是什么?一个令人困惑的是:

...
\cs_new_protected:Npn \user_name_refs:nnnn #1#2#3#4
{
  ...

我理解这\user_name_refs:nnnn #1#2#3#4指的是我的函数名为\user_name_refs接收 4 个参数nnnn,它们是 。但是里面在做Unexpanded token or braced token list什么呢?Npn\cs_new_protected:Npn

这些Npm论点似乎与expl3封装和LATEX3编程

所有函数均具有基本形式,其参数使用下列参数说明符之一:

  1. n未扩展的标记或带括号的标记列表。

    这是一个标准的 TEX 无界宏参数。

  2. N单个标记(与 n 不同,参数不能被括号括起来)。

    接受 N 个参数的命令的典型示例是\cs_set,其中定义的命令必须是无括号的。

  3. p原始 TEX 参数规范。

    这可以是像 这样的简单内容#1#2#3,但可以使用任意分隔参数语法,例如:#1,#2\q_stop#3。这在定义函数时使用。

  4. T,F这些是 n 个参数的特殊情况,用于条件命令中的真和假代码。

    ...

扩展控制系统中还有其他参数说明符。下一节将讨论这些内容。Expansion control

事实上,这expl3封装和LATEX3编程,看起来相当完整。还有其他的吗?没有\cs_new_protected提到expl3封装和LATEX3编程指南。是否应该将其添加到其中?

在这些问题上,我可以找到关于以下内容的小提示\cs_new_protected

  1. 在 LaTeX3 中将标记转换为字符串

    您必须对要检查的字符进行循环。请注意, 和 都不可\str_if_in:nnTF扩展\peek_after:Nw,因此\cs_new_protected:Nn应使用 。

  2. 在 LaTeX2e 宏中使用 expl3

    而不是\newcommand,最好使用\cs_new_protected:Npn,如果不是\NewDocumentCommandxparse甚至可能是更好的选择)。

  3. LaTeX3 新的宏/函数定义问题

    如果你要定义的命令没有签名,你必须\cs_new:Npn用或 来定义它\cs_new_protected:Npn

    请注意,当代码包含不可扩展函数(手册中没有红色实心或空心星号的函数)时,应使用\cs_new_protected:Npn或(适用相同规则)。这里不是这种情况,因为是完全可扩展的。\cs_new_protected:Nn\int_eval:n

  4. 理解可扩展性的指南:何时编写受保护的函数以及何时不编写受保护的函数

    因此,编写 LaTeX3 代码的“正确”方法是使用任何事物不可扩展(IE未在文档中加星号)在你的代码中,那么你使用\cs_new_protected:Npn或类似用途,以及不是 \cs_new:NpnETC。

  5. latex3 抱怨未定义的控制序列。但它已定义!

    \cs_new_protected:Npn当函数执行不可扩展的工作(例如设置标记列表或序列)时使用。

但没有明确的解释这些Npm论点是什么\cs_new_protected......虽然,LaTeX3:使用 :o 定义宏的正确方法,在引用The LATEX3 interfacesl3kernel – LATEX3 编程约定

没有什么魔法。当你说 时\cs_new_protected:Nn,你正在使用\def\gdef伪装。……毫无疑问,一步一步来会更好:

\cs_new_protected:Nn \__a_one:n
{
    ...
}
\cs_generate_variant:Nn \__a_one:n { o }

因为\__a_one:n无论如何都要定义该函数。因此没有必要为此设置复杂的机制。

更具体地说,在该代码之后,的含义\__a_one:o

\exp_args:No \__a_one:n

...

\cs_new_protected:Nn \__a_one:o对于假设处理所需的扩展来说,没有其他实际的方法可以从\__a_one:n根本上进行定义,然后应用\cs_generate_variant:Nn

因此,我必须将其\cs_new_protected与 一起使用\cs_generate_variant:Nn。但这是什么\exp_args:No \__a_one:n意思?然后,同样的问题适用于:

  1. \cs_generate_variant:Nn干啥?
  2. 什么\cs_new_protected是?函数?修饰符?保留关键字?函数声明语法?

相关问题

  1. 类似 \cs_generate_variant:Nn \foo_my_func:n { N } 之类的操作会引发错误吗?
  2. 什么是函数的签名?[LaTeX3]
  3. expl3 函数用于固定数量的扩展步骤
  4. 是否可以将控制序列类型的 LaTeX3 变量的声明与设置其值的行为分开?
  5. LaTeX3 中的 \use_none_delimit_by_q_nil:w 及其朋友的用途是什么?
  6. LaTeX3 迭代和标记列表比较-代码改进
  7. 定义一个可扩展函数,用于在 LaTeX3 中将标记列表与字符串进行比较
  8. f 型展开
  9. 使用 expl3 编写条件标记列表
  10. expl3 中的受保护扩展
  11. 在 LaTeX3 中向映射函数传递更多参数
  12. expl3“数据类型”的效率和速度
  13. 如何测试一个 token 变量是否存在?
  14. LaTeX3 简介中的完整示例
  15. 为什么 LaTeX3 命令中有这么多下划线?
  16. 如何使用 \cs_generate_variant:Nn 比较标记列表?
  17. 将 LaTeX3 标记列表与字符串进行比较

答案1

在 中expl3,每个函数名都有两部分:首先是函数基本名称(不确定这是否是它的实际名称,但我将在本文中这样称呼它以使区别更清楚),类似于 TeX 或 LaTeX2 宏名称,但其中带有可选的下划线,之后是参数说明符列表,用冒号与基本名称分隔。

这里最重要的部分是参数说明符是函数名称的一部分!您不能忽略它们,并且微小的变化可能会导致不同的函数行为。

什么\cs_new_protected是?函数?修饰符?保留关键字?函数声明语法?

\cs_new_protected是定义新的、受保护的长函数/宏的函数集的基本名称。您不能直接使用此基本名称,但必须添加参数说明符才能使其成为完整的函数名称。

这组函数中最常见的是\cs_new_protected:Npn。正如您在问题中指出的那样,说明符列表表示以下内容:

  • N是要定义的新函数的全名,
  • p是一个参数文本参数,它将构成新定义函数的参数文本,并且
  • n是一个普通的、带括号的参数,它保存着新定义函数的替换文本的标记。

因此

\cs_new_protected:Npn \myfunc #1#2 { ...#1...#2... }

相当于 TeX 定义

\long\protected\gdef\myfunc#1#2{...#1...#2...}

加上一些额外的健全性检查。根据expl3命名约定,您应该在函数名称前加上模块名称并添加参数说明符,因此真正的 LaTeX3 名称看起来应该类似于\user_myfunc:nn

\cs_generate_variant:Nn干啥?

如上所述,通常有多个不同的函数具有相同的基本名称,但具有不同的参数说明符,它们都代表不同的函数。通用的基本名称只是表明它们的行为足够相似。

例如,上述函数\cs_new_protected:Npn也存在于\cs_new_proctected:Npx与变体基本相同的变体中Npn,但具有完全扩展的替换文本,即\xdef而不是\gdefTeX 等效项中的变体。

\cs_generate_variant:Nn我们只需提供原始的完整函数名称(N)和要派生函数的参数说明符(n),即可从基本变体自动派生新的函数变体。

例如,我们可以派生一个变体,\user_myfunc:nn其中第一个参数必须完全展开,第二个参数应从变量名中获取,然后通过调用作为括号参数传递给原始函数

\cs_generate_variant:Nn \user_myfunc:nn { xV }

此后我们\user_myfunc:xV在范围内有了一个新功能。

关于哪个函数可以从哪个函数派生有一些规则,例如,您只能使用具有Nn参数的变体来派生新函数,或者您只能xn基参数派生变体,但c变体只能从基参数派生,等等。此外,对于条件参数和N还有特殊处理。您可以在文档的部分中找到完整的规则。TFl3expanexpl3

相关内容