如果使用键值参数定义命令,例如\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}
这给出了所需的结果