处理嵌套命令的(默认)键值

处理嵌套命令的(默认)键值

如果使用键值参数定义命令,例如\ket[<key=value>]{<stuff>},嵌套时会得到错误的输出(在我看来)。例如,\ket[delim = |)]{ \ket{\psi} }更改两个键的分隔符,但只应对外部键执行此操作,如果\ket定义为

\NewDocumentCommand{\ket}{ o m }
{
\group_begin:
    \IfNoValueF{#1} { \mymodule_set_keys:n {#1} }
    \mymodule_ket:n {#2}
\group_end:
}

o一个快速的解决方案是,当没有给出 -argument时,将键设置为其默认值,如下所示。

\NewDocumentCommand{\ket}{ o m }
{
\group_begin:
    \IfNoValueTF{#1}
      { \mymodule_set_keys:n { delim } }
      { \mymodule_set_keys:n {#1} }
    \mymodule_ket:n {#2}
\group_end:
}

该解决方案不允许用户进行任何更改\mymoduleset(在下面的 MWE 评论中,我将其称为‘用户默认’),比如说\mymoduleset[delim = \langle|]

\ket这个想法是,当定义命令时,它应该最初使用包的默认值,即delim .default:n = {\lvert\rangle},但是当用户想要所有\ket的(某种意义上是全局的)不同的输出时,他可以使用来改变它\mymoduleset,这样当使用时\ket{<stuff>}就会产生。\langle <stuff> |\mymoduleset[delim = \langle|]

如何才能找到解决方案,

  • 允许用户使用“全局”更改\mymoduleset
  • 并且局部变化\ket[<key=value>]{<stuff>}不会影响内部\ket变化\ket[delim = |)]{ \ket{\psi} }

平均能量损失

\documentclass{article}
\usepackage{xparse}
\usepackage{amsmath}

\ExplSyntaxOn

\tl_new:N \l__mymodule_ket_delim_tl

\keys_define:nn { mymodule }
{
    delim .tl_set:N  = \l__mymodule_ket_delim_tl,
    delim .default:n = {\lvert\rangle}
}

\cs_new_protected:Npn \mymodule_ket:n #1
{
    \tl_item:Nn \l__mymodule_ket_delim_tl {1}
    #1
    \tl_item:Nn \l__mymodule_ket_delim_tl {2}
}

\cs_new_protected:Npn \mymodule_set_keys:n #1
{ \keys_set:nn { mymodule } {#1} }

\NewDocumentCommand{\ket}{ o m }
{
\group_begin:
    \IfNoValueTF{#1}
    { \mymodule_set_keys:n { delim } } % package default, but should be user default
    { \mymodule_set_keys:n {#1} }      % local change for this macro only

    \mymodule_ket:n {#2}
\group_end:
}

\NewDocumentCommand{\mymoduleset}{ o }
{
    \IfNoValueTF{#1}
    { \mymodule_set_keys:n { delim } } % Package default
    { \mymodule_set_keys:n {#1}      } % User default
}
\ExplSyntaxOff
\mymoduleset

\begin{document}
    \begin{align}
        \ket{\psi}                     &\quad \text{desired result: } | \psi \rangle \\
        \ket{ \ket{\psi} }             &\quad \text{desired result: } || \psi \rangle\rangle \\
        \ket[delim = |)]{ \ket{\psi} } &\quad \text{desired result: } || \psi \rangle ) \\
        \ket{ \ket[delim = |)]{\psi} } &\quad \text{desired result: } || \psi ) \rangle
    \end{align}

    \mymoduleset[delim = {\langle\rvert}]

    \begin{align}
        \ket{\psi}                     &\quad \text{desired result: } \langle \psi | \\
        \ket{ \ket{\psi} }             &\quad \text{desired result: } \langle\langle \psi || \\
        \ket[delim = (|]{ \ket{\psi} } &\quad \text{desired result: } ( \langle \psi || \\
        \ket{ \ket[delim = (|]{\psi} } &\quad \text{desired result: } \langle ( \psi ||
    \end{align}
\end{document}

在此处输入图片描述

注意:上面的 MWE 不是实际用例,但说明了问题。实际用例太长了,这里就不写了

答案1

您可以使用元键。

\documentclass{article}
\usepackage{xparse}
\usepackage{amsmath}

\ExplSyntaxOn

\tl_new:N \l__mymodule_ket_delim_tl

\keys_define:nn { mymodule }
 {
  delim   .tl_set:N = \l__mymodule_ket_delim_tl,
 }

\cs_new_protected:Npn \mymodule_ket:n #1
 {
  \tl_item:Nn \l__mymodule_ket_delim_tl {1}
  #1
  \tl_item:Nn \l__mymodule_ket_delim_tl {2}
 }

\cs_new_protected:Npn \mymodule_set_keys:n #1
 {
  \keys_set:nn { mymodule } {#1}
 }

\NewDocumentCommand{\ket}{ O{} m }
 {
  \group_begin:
  \mymodule_set_keys:n {default,#1} % local change for this macro only
  \mymodule_ket:n {#2}
  \group_end:
 }

\NewDocumentCommand{\mymoduleset}{m}
 {
  \keys_define:nn { mymodule }
   {
    default .meta:n = { #1 }
   }
 }

\ExplSyntaxOff

% initialize
\mymoduleset{delim=\lvert\rangle}

\begin{document}

\begin{align}
  \ket{\psi}                     &\quad \text{desired result: } | \psi \rangle \\
  \ket{ \ket{\psi} }             &\quad \text{desired result: } || \psi \rangle\rangle \\
  \ket[delim = |)]{ \ket{\psi} } &\quad \text{desired result: } || \psi \rangle ) \\
  \ket{ \ket[delim = |)]{\psi} } &\quad \text{desired result: } || \psi ) \rangle
\end{align}

\mymoduleset{delim = \langle\rvert}

\begin{align}
  \ket{\psi}                     &\quad \text{desired result: } \langle \psi | \\
  \ket{ \ket{\psi} }             &\quad \text{desired result: } \langle\langle \psi || \\
  \ket[delim = (|]{ \ket{\psi} } &\quad \text{desired result: } ( \langle \psi || \\
  \ket{ \ket[delim = (|]{\psi} } &\quad \text{desired result: } \langle ( \psi ||
\end{align}

\end{document}

在此处输入图片描述

答案2

正如 Joseph 所评论的那样,我寻求的解决方案超出了 TeX 中分组的工作方式。因此,我想出了一个变通的解决方案,我将用户默认值存储在一个序列中,并用它来将\ket键设置为用户默认值。虽然我无法阻止“本地更改”,即\ket[<key=value>]{<stuff>}影响内部键,但我始终可以使用此序列来覆盖本地更改,因此它们实际上仅适用于一个命令。

\documentclass{article}
\usepackage{xparse}
\usepackage{amsmath}

\ExplSyntaxOn

\tl_new:N \l__mymodule_ket_delim_tl
\seq_new:N \l__mymodule_user_default_seq

\seq_const_from_clist:Nn \l__mymodule_pkg_default_seq { delim }

\keys_define:nn { mymodule }
{
    delim .tl_set:N  = \l__mymodule_ket_delim_tl,
    delim .default:n = {\lvert\rangle}
}

\cs_new_protected:Npn \mymodule_ket:n #1
{
    \tl_item:Nn \l__mymodule_ket_delim_tl {1}
    #1
    \tl_item:Nn \l__mymodule_ket_delim_tl {2}
}

\cs_new_protected:Npn \mymodule_set_keys:n #1
{ \keys_set:nn { mymodule } {#1} }

\cs_new_protected:Npn \mymodule_new_ket:N #1
{
    \NewDocumentCommand{#1}{ o m }
    {
    \group_begin:
        % Use user default
        \exp_args:Nf \mymodule_set_keys:n { \seq_use:Nn \l__mymodule_user_default_seq {,} }
        \IfNoValueF{##1}
        {
            % local change
            \mymodule_set_keys:n {##1}
        }

        \mymodule_ket:n {##2}
    \group_end:
    }
}

\NewDocumentCommand{\NewKet}{ m o }
{
    \seq_set_eq:NN \l__mymodule_user_default_seq \l__mymodule_pkg_default_seq
    \IfNoValueTF{#2}
    {
        % Set to package default
        \mymodule_set_keys:n { delim }
    }
    {
        % Set to user default
        \mymodule_set_keys:n {#2}
        \seq_put_right:Nn \l__mymodule_user_default_seq {#2}
    }
    \mymodule_new_ket:N #1
}

\NewDocumentCommand{\mymoduleset}{ o }
{
    \IfNoValueTF{#1}
    {
        % Set to package default
        \mymodule_set_keys:n { delim }
        \seq_set_eq:NN \l__mymodule_user_default_seq \l__mymodule_pkg_default_seq
    }
    {
        % Set to user default
        \mymodule_set_keys:n {#1}
        \seq_put_right:Nn \l__mymodule_user_default_seq {#1}
    }
}

\ExplSyntaxOff

\NewKet{\ket}

\begin{document}
    \begin{align}
        \ket{\psi}                     &\quad \text{desired result: } | \psi \rangle \\
        \ket{ \ket{\psi} }             &\quad \text{desired result: } || \psi \rangle\rangle \\
        \ket[delim = |)]{ \ket{\psi} } &\quad \text{desired result: } || \psi \rangle ) \\
        \ket{ \ket[delim = |)]{\psi} } &\quad \text{desired result: } || \psi ) \rangle
    \end{align}

    \mymoduleset[delim = {\langle\rvert}]

    \begin{align}
        \ket{\psi}                     &\quad \text{desired result: } \langle \psi | \\
        \ket{ \ket{\psi} }             &\quad \text{desired result: } \langle\langle \psi || \\
        \ket[delim = (|]{ \ket{\psi} } &\quad \text{desired result: } ( \langle \psi || \\
        \ket{ \ket[delim = (|]{\psi} } &\quad \text{desired result: } \langle ( \psi ||
    \end{align}
\end{document}

这给出了所需的结果

在此处输入图片描述

相关内容