我有一个命令,\Baz
它接受一个可选参数,该参数必须是内联代码。它依赖于外部变量来存储默认的内联代码 (1)。作为独立程序,它可以工作,但它不符合我正在开发的项目的要求 (2)。这就是\Foo
定义它的地方,以及一个元命令 (3),进入图片。问题:当我尝试定义时\Foo
,我收到错误:Defaults of '\Foo' have circular dependency
。
附注:(1)将默认值保留在外部的原因是为了能够通过\Baz
这种方式进行修改。(2)序列化调用\Baz
:有关默认值的信息会丢失。(3)暂定解决方案借鉴了发布请求创建 lambda 函数。
\documentclass{report}
\usepackage{xparse}
\ExplSyntaxOn
\cs_set:Npn \__erw_baz_default:n #1{Hello, #1!}
\cs_set:Npn \__erw_baz_set:n #1
{
\cs_gset:Npn \__erw_baz:n ##1 {#1}
}
\DeclareDocumentCommand{\Baz}
{O{\__erw_baz_default:n{##1}}}
{
\__erw_baz_set:n {#1}
\__erw_baz:n{world}
}
\cs_set:Npn \__erw_foo_set:n #1
{
\cs_gset:Npn \__erw_foo:n ##1 {#1}
}
\cs_new_protected:Npn \__erw_make_Foo:n
#1
{
\use:x
{
\exp_not:n{\DeclareDocumentCommand{\Foo}}
{O{#1}}
}
{
\__erw_foo_set:n{##1}
\__erw_foo:n{world}
}
}
\__erw_make_Foo:n{Hello, ##1!}
\NewDocumentCommand{\Test}
{}
{
\noindent
\Baz[Jello,~##1!]\\
\Baz\\
\Foo[Jello,~##1!]\\
%\Foo
% Expected: % Hello, world!
% Actual: % LaTeX3 Error: Defaults of '\Foo' have circular dependency
}
\ExplSyntaxOff
\begin{document}
\Test
\end{document}
答案1
“您是否尝试过将其关闭然后重新打开?”的 TeX 对应语句是“您是否尝试过将哈希值加倍或减半?”
当\__erw_make_Foo:n {Hello, ##1!}
扩展并且参数被消耗时,当 TeX 将的参数替换\__erw_make_Foo:n
到其定义中时,哈希值会减半,因此您有:
\DeclareDocumentCommand \Foo { O{Hello, #1!} }
{
\__erw_foo_set:n {#1}
\__erw_foo:n { world }
}
正如所宣传的那样,xparse
这是一个循环定义。如果没有给出可选参数,则的默认值#1
取决于的值#1
,而的值又取决于的值#1
,而的值又取决于...
如果在调用时将哈希值加倍,\__erw_make_Foo:n
则会得到:
\DeclareDocumentCommand \Foo { O{Hello, ##1!} }
{
\__erw_foo_set:n {#1}
\__erw_foo:n { world }
}
#1
当您使用时它会插入一个参数\__erw_foo_set:n
。
您的一些缺点expl3
:
不可扩展的宏(例如,如果它们执行分配)必须用 来定义
protected
,所以\cs_new_protected:Npn
不用\cs_new:Npn
。不带 的版本protected
严格用于可扩展(按设计)宏;\cs_set(_protected):Npn
除非你真的需要,否则请避免使用。(正确使用)的优点之一expl3
是你可以避免与其他包的名称冲突以及意外覆盖宏。如果你使用,\cs_set:Npn
你就会忽略这一点。使用;\cs_new(_protected):Npn
\exp_args:NNx \DeclareDocumentCommand \Foo { O{#1} }
比 稍微容易一些\use:x { \exp_not:n { \DeclareDocumentCommand \Foo } { O{#1} } }
;缩进代码:-)
代码如下:
\documentclass{report}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new:Npn \__erw_baz_default:n #1 { Hello,~#1! }
\cs_new_protected:Npn \__erw_baz_set:n #1
{ \cs_gset:Npn \__erw_baz:n ##1 {#1} }
\NewDocumentCommand \Baz { O{ \__erw_baz_default:n {##1} } }
{
\__erw_baz_set:n {#1}
\__erw_baz:n { world }
}
\cs_new_protected:Npn \__erw_foo_set:n #1
{ \cs_gset:Npn \__erw_foo:n ##1 {#1} }
\cs_new_protected:Npn \__erw_make_Foo:n #1
{
\exp_args:NNx \DeclareDocumentCommand \Foo { O{#1} }
{
\__erw_foo_set:n {##1}
\__erw_foo:n { world }
}
}
\NewDocumentCommand \Test { }
{
\noindent
\Baz[Jello,~##1!]\\
\Baz\\
\Foo[Jello,~##1!]\\
\Foo
}
\__erw_make_Foo:n {Hello, ####1!}
\ExplSyntaxOff
\begin{document}
\Test
\end{document}