自定义参数规范:'\Foo' 的默认值具有循环依赖性

自定义参数规范:'\Foo' 的默认值具有循环依赖性

我有一个命令,\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}

相关内容