在我提出问题之后向现有 \ExplSyntaxOn 代码添加新参数时未定义控制序列,我试图完全理解其背后的代码。到目前为止,一切顺利,有:
- 这
expl3
封装和LATEX3
编程 - https://www.texdev.net/2010/05/23/from-newcommand-to-newdocumentcommand/
- 在 \NewDocumentCommand 中使用键值
- 总是使用 \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
编程
所有函数均具有基本形式,其参数使用下列参数说明符之一:
n
未扩展的标记或带括号的标记列表。这是一个标准的 TEX 无界宏参数。
N
单个标记(与 n 不同,参数不能被括号括起来)。接受 N 个参数的命令的典型示例是
\cs_set
,其中定义的命令必须是无括号的。
p
原始 TEX 参数规范。这可以是像 这样的简单内容
#1#2#3
,但可以使用任意分隔参数语法,例如:#1,#2\q_stop#3
。这在定义函数时使用。
T,F
这些是 n 个参数的特殊情况,用于条件命令中的真和假代码。...
扩展控制系统中还有其他参数说明符。下一节将讨论这些内容。
Expansion control
。
事实上,这这expl3
封装和LATEX3
编程,看起来相当完整。还有其他的吗?没有\cs_new_protected
提到这expl3
封装和LATEX3
编程指南。是否应该将其添加到其中?
在这些问题上,我可以找到关于以下内容的小提示\cs_new_protected
:
- 在 LaTeX3 中将标记转换为字符串
您必须对要检查的字符进行循环。请注意, 和 都不可
\str_if_in:nnTF
扩展\peek_after:Nw
,因此\cs_new_protected:Nn
应使用 。 - 在 LaTeX2e 宏中使用 expl3
而不是
\newcommand
,最好使用\cs_new_protected:Npn
,如果不是\NewDocumentCommand
(xparse
甚至可能是更好的选择)。 - LaTeX3 新的宏/函数定义问题
如果你要定义的命令没有签名,你必须
\cs_new:Npn
用或 来定义它\cs_new_protected:Npn
。请注意,当代码包含不可扩展函数(手册中没有红色实心或空心星号的函数)时,应使用
\cs_new_protected:Npn
或(适用相同规则)。这里不是这种情况,因为是完全可扩展的。\cs_new_protected:Nn
\int_eval:n
- 理解可扩展性的指南:何时编写受保护的函数以及何时不编写受保护的函数
因此,编写 LaTeX3 代码的“正确”方法是使用任何事物不可扩展(IE未在文档中加星号)在你的代码中,那么你有使用
\cs_new_protected:Npn
或类似用途,以及不是\cs_new:Npn
,ETC。 - latex3 抱怨未定义的控制序列。但它已定义!
\cs_new_protected:Npn
当函数执行不可扩展的工作(例如设置标记列表或序列)时使用。
但没有明确的解释这些Npm
论点是什么\cs_new_protected
......虽然,LaTeX3:使用 :o 定义宏的正确方法,在引用The LATEX3 interfaces
了l3kernel – 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
意思?然后,同样的问题适用于:
- 在
\cs_generate_variant:Nn
干啥? - 什么
\cs_new_protected
是?函数?修饰符?保留关键字?函数声明语法?
相关问题
- 类似 \cs_generate_variant:Nn \foo_my_func:n { N } 之类的操作会引发错误吗?
- 什么是函数的签名?[LaTeX3]
- expl3 函数用于固定数量的扩展步骤
- 是否可以将控制序列类型的 LaTeX3 变量的声明与设置其值的行为分开?
- LaTeX3 中的 \use_none_delimit_by_q_nil:w 及其朋友的用途是什么?
- LaTeX3 迭代和标记列表比较-代码改进
- 定义一个可扩展函数,用于在 LaTeX3 中将标记列表与字符串进行比较
- f 型展开
- 使用 expl3 编写条件标记列表
- expl3 中的受保护扩展
- 在 LaTeX3 中向映射函数传递更多参数
- expl3“数据类型”的效率和速度
- 如何测试一个 token 变量是否存在?
- LaTeX3 简介中的完整示例
- 为什么 LaTeX3 命令中有这么多下划线?
- 如何使用 \cs_generate_variant:Nn 比较标记列表?
- 将 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
而不是\gdef
TeX 等效项中的变体。
\cs_generate_variant:Nn
我们只需提供原始的完整函数名称(N
)和要派生函数的参数说明符(n
),即可从基本变体自动派生新的函数变体。
例如,我们可以派生一个变体,\user_myfunc:nn
其中第一个参数必须完全展开,第二个参数应从变量名中获取,然后通过调用作为括号参数传递给原始函数
\cs_generate_variant:Nn \user_myfunc:nn { xV }
此后我们\user_myfunc:xV
在范围内有了一个新功能。
关于哪个函数可以从哪个函数派生有一些规则,例如,您只能使用具有N
或n
参数的变体来派生新函数,或者您只能x
从n
基参数派生变体,但c
变体只能从基参数派生,等等。此外,对于条件参数和N
还有特殊处理。您可以在文档的部分中找到完整的规则。T
F
l3expan
expl3