在下面的 MWE 中NewDocumentCommands
\myComparison
,和\myNewComparison
都使用一个控制序列\cookbook_Compare:nn
,该序列被输入两个要比较的 tokenlist 参数。这些参数被定义为可选O{}
类型参数;在\myComparison
默认值是按字面定义的,而在\myNewComparison
它们是通过变量定义的tokenlist
。调用 1.、2. 和 3. 的\myComparison
工作符合预期,调用 4. 和 5. 也是如此\myNewComparison
。但是,如果\myNewComparison
像在 6. 中那样不带参数地调用,则\tl_if_eq:NNTF
在比较两个内容相同的变量时会得出错误的答案tokenlist
。为什么?
\usepackage[check-declarations]{expl3}
\usepackage{xparse}
% ----------------------------------------
\ExplSyntaxOn
% VARIABLE DECLARATIONS:
\tl_new:N \l_rn_OpOne_tl
\tl_new:N \l_rn_OpTwo_tl
\tl_new:N \l_rn_OpOneDefault_tl
\tl_new:N \l_rn_OpTwoDefault_tl
\tl_set:Nn \l_rn_OpOneDefault_tl {abc}
\tl_set:Nn \l_rn_OpTwoDefault_tl {abc}
% ----------------------------------------
\NewDocumentCommand\myComparison{O{abc}O{abc}}
{
\cookbook_Compare:nn {#1}{#2}
}
\NewDocumentCommand\myNewComparison{O{\l_rn_OpOneDefault_tl}O {\l_rn_OpTwoDefault_tl}}
{
\cookbook_Compare:nn {#1}{#2}
}
\cs_new_protected:Npn \cookbook_Compare:nn #1 #2
{
\tl_set:Nn \l_rn_OpOne_tl {#1}
\tl_set:Nn \l_rn_OpTwo_tl {#2}
Op~1:~\l_rn_OpOne_tl\\
Op~2:~\l_rn_OpTwo_tl\\
Op~1~=~ Op~2~
\tl_if_eq:NNTF \l_rn_OpOne_tl \l_rn_OpTwo_tl
{TRUE\\}{FALSE\\}
}
\ExplSyntaxOff
\begin{document}
1. \verb+\myComparison[zz][zz]+:\\
\myComparison[zz][zz]
2. \verb+\myComparison[1z][zz]+:\\
\myComparison[1z][zz]
3. \verb+\myComparison+:\\
\myComparison
4. \verb+\myNewComparison[zz][zz]+:\\
\myNewComparison[zz][zz]
5. \verb+\myNewComparison[1z][zz]+:\\
\myNewComparison[1z][zz]
6. \verb+\myNewComparison+:\\
\myNewComparison
\end{document}
答案1
标记列表等价性的测试不是“它们最终是否扩展为相同的东西”,而是“它们是否具有相同的内容”。使用你的代码,你实际上最终会得到
\tl_set:Nn \l_rn_OpOne_tl {\l_rn_OpOneDefault_tl}
\tl_set:Nn \l_rn_OpTwo_tl {\l_rn_OpTwoDefault_tl}
它们是不相等的:它们包含不同的 tl 变量,但碰巧具有相同的内容。
如果您想比较此处的内容,并且还想允许文字和存储的输入,那么您必须使用 强制扩展至“文本” \tl_set:Nx
。 风险在于使用 LaTeX2e 输入时,您可能会遇到脆弱的命令,因此除非您处于非常受限的情况,\protected@edef
否则您应该使用。 (expl3
不提供后者的任何等效项,因为“原生”LaTeX3 材料不需要 LaTeX2e 稳健机制。)
答案2
您必须使用不同的方式来测试可选参数,以便您可以比较正确的标记;否则,您正在比较\l_rn_OpOneDefault_tl
(\l_rn_OpTwoDefault_tl
而不是变量的内容)。
\documentclass{article}
\usepackage[check-declarations]{expl3}
\usepackage{xparse}
% ----------------------------------------
\ExplSyntaxOn
% VARIABLE DECLARATIONS:
\tl_new:N \l_rn_OpOne_tl
\tl_new:N \l_rn_OpTwo_tl
\tl_new:N \l_rn_OpOneDefault_tl
\tl_new:N \l_rn_OpTwoDefault_tl
\tl_set:Nn \l_rn_OpOneDefault_tl {abc}
\tl_set:Nn \l_rn_OpTwoDefault_tl {abc}
% ----------------------------------------
\NewDocumentCommand\myComparison{O{abc}O{abc}}
{
\cookbook_Compare:nn {#1}{#2}
}
\NewDocumentCommand\myNewComparison{oo}
{
\IfNoValueTF{#1}
{ \cookbook_Compare:VV \l_rn_OpOneDefault_tl \l_rn_OpTwoDefault_tl }
{
\IfNoValueTF{#2}
{ \cookbook_Compare:nV { #1 } \l_rn_OpTwoDefault_tl }
{ \cookbook_Compare:nn { #1 } { #2 } }
}
}
\cs_new_protected:Npn \cookbook_Compare:nn #1 #2
{
\tl_set:Nn \l_rn_OpOne_tl {#1}
\tl_set:Nn \l_rn_OpTwo_tl {#2}
Op~1:~\l_rn_OpOne_tl\\
Op~2:~\l_rn_OpTwo_tl\\
Op~1~=~ Op~2~
\tl_if_eq:NNTF \l_rn_OpOne_tl \l_rn_OpTwo_tl
{TRUE\\}{FALSE\\}
}
\cs_generate_variant:Nn \cookbook_Compare:nn { nV , VV }
\ExplSyntaxOff
\begin{document}
1. \verb+\myComparison[zz][zz]+:\\
\myComparison[zz][zz]
2. \verb+\myComparison[1z][zz]+:\\
\myComparison[1z][zz]
3. \verb+\myComparison+:\\
\myComparison
4. \verb+\myNewComparison[zz][zz]+:\\
\myNewComparison[zz][zz]
5. \verb+\myNewComparison[1z][zz]+:\\
\myNewComparison[1z][zz]
6. \verb+\myNewComparison+:\\
\myNewComparison
\end{document}