建议将所有命令参数作为列表传递

建议将所有命令参数作为列表传递

我已经在一个又一个的线索中徘徊了一段时间,但仍然无法理解我的问题。

我想做一些我认为很基本​​的事情;声明一个“内积”命令,该命令接受两个强制参数并将它们打印在括号中。比如

内积示例

现在,一个简单的方法是

\NewDocumentCommand\innerproduct{mm}{\left\langle{#1}\,,{#2}\right\rangle}

所以我可以通过执行 来获得示例\innerproduct{a}{b}。但\innerproduct{a,b}会更好,这就是我不确定如何继续的地方。我阅读了有关参数处理器的内容,并尝试了

\NewDocumentCommand\privateip{mm}{\left\langle{#1}\,,{#2}\right\rangle}
\NewDocumentCommand\innerproduct{>{\SplitArgument{1}{,}}m}{\privateip#1}

它确实能完成任务,但对我来说有点不稳定,因为我不想每次想要完成任务时都定义两个命令。 这两个命令可以捆绑在一起吗?

有一些通过以(对我来说)晦涩的方式迭代列表来做各种很酷的事情的例子,但我认为我想要的要简单得多:确保两个参数存在,并且能够访问它们来打印它们。


编辑:感谢您的众多回答!

稍微澄清一下,我担心的不是具有定义一系列命令来实现我的结果,但命名空间很混乱。我的例子很简单,但我希望我可以将答案推广到其他情况。

我不知道,但我喜欢这种方法,它确实完美地满足了这个用例。我以后mathtools也会检查一下。这就是我现在的情况:semantex

\makeatletter
\DeclarePairedDelimiterXPP\p@ip[3]{}\langle\rangle{\ifblank{#3}{}{_#3}}{#1\,,#2}
    \NewDocumentCommand\innerproduct{so>{\SplitArgument{1}{,}}mO{}}{%
        \IfBooleanTF{#1}{%
            \p@ip*#3{#4}%
        }{%
            \IfNoValueTF{#2}{\p@ip#3{#4}}{\p@ip[#2]#3{#4}}%
        }%
    }
\makeatother

我不知道我怎么会错过它,但我用了一些@魔法来解决我的混乱问题。可选的星号或大小参数可以正常使用,我得到了目标行为\innerproduct{a,b},并且我添加了一个可选的后缀,我需要用它来区分运算符(这需要一些间距调整,但这是另一个问题)。好极了!

$\innerproduct[\Big]{\frac12,y}$

$\innerproduct[\Bigg]{\frac12,y}$

$\innerproduct*{\frac12,y}$

$\innerproduct*{\frac12,y}[A]$

$\innerproduct{\frac12,y}[A]$

$\innerproduct[\big]{\frac12,y}[A]$

在此处输入图片描述

仍然热衷于任何评论。

答案1

在你的情况下,只需定义

\DeclarePairedDelimiter{\innerproduct}{\langle}{\rangle}

你就完成了,因为如果你输入

\innerproduct{a,b}

参数已经是预期格式。无需拆分逗号分隔列表即可重建它。

但是……是的,还有更多。假设你的合著者喜欢物理学家喜爱的“bra-ket”符号,而你不想或不能争论这个选择。你的文本已经充满了\innerproduct{a,b}或可能\innerproduct[\Big]{x,y}(当然,其中x,y需要\Big),你不想承担以某种方式改变一切的负担。

好的,现在我们可以用一种非常简单的方法解决这个问题。我们仍然使用 的基础设施,但还mathtools需要更先进的。\DeclarePairedDelimiterX\NewDocumentCommand

\DeclarePairedDelimiterX{\innerproduct}[1]{\langle}{\rangle}{\makebraket{#1}}
\NewDocumentCommand{\makebraket}{>{\SplitArgument{1}{,}}m}{\makebraketaux#1}
\NewDocumentCommand{\makebraketaux}{mm}{#1\;\delimsize\vert\;#2}

因此\innerproduct本质上与以前相同,但它还将委托\makebraket给以逗号分隔列表(两个项目)给出的参数的处理。

使用>{\SplitArgument{1}{c}}m,给定的参数a,b将被传递给下面的代码,因为{a}{b},所以我们必须定义\makebraketaux为有两个参数。

完整示例:

\documentclass{article}
\usepackage{mathtools}

% my preferred way, but my coauthor doesn't like it :-(
% \DeclarePairedDelimiter{\innerproduct}{\langle}{\rangle}
% here's for the bra-ket way
\DeclarePairedDelimiterX{\innerproduct}[1]{\langle}{\rangle}{\makebraket{#1}}
\NewDocumentCommand{\makebraket}{>{\SplitArgument{1}{,}}m}{\makebraketaux#1}
\NewDocumentCommand{\makebraketaux}{mm}{#1\;\delimsize\vert\;#2}

\begin{document}

\[
\innerproduct{a,b}
\quad
\innerproduct[\big]{a,b}
\quad
\innerproduct[\Big]{\frac{x}{2},\frac{y}{2}}
\quad
\innerproduct[\bigg]{\frac{x}{2},\frac{y}{2}}
\quad
\innerproduct*{\frac{x}{2},\frac{y}{2}}
\]

\end{document}

在此处输入图片描述

如果你担心宏泛滥,不必担心。TeX 编程通常需要这样做,要么是为了简化代码,要么是因为无法避免使用辅助宏(例如递归)。>{\SplitArgument{1}{,}}以后者为例,不用担心:级联宏是 TeX 程序员的日常主食。

现在,事实证明我忽略了您的要求,但这与部分内容基本相同\makebraket

\documentclass{article}
\usepackage{mathtools}

\DeclarePairedDelimiterX{\innerproduct}[1]{\langle}{\rangle}{\addthinspace{#1}}
\NewDocumentCommand{\addthinspace}{>{\SplitArgument{1}{,}}m}{\addthinspaceaux#1}
\NewDocumentCommand{\addthinspaceaux}{mm}{#1\,,#2}

\begin{document}

\[
\innerproduct{a,b}
\quad
\innerproduct[\big]{a,b}
\quad
\innerproduct[\Big]{\frac{x}{2},\frac{y}{2}}
\quad
\innerproduct[\bigg]{\frac{x}{2},\frac{y}{2}}
\quad
\innerproduct*{\frac{x}{2},\frac{y}{2}}
\]

\end{document}

在此处输入图片描述

几乎没有任何辅助设备的版本:

\DeclarePairedDelimiterX{\innerproduct}[1]{\langle}{\rangle}{\addthinspace{#1}}

\ExplSyntaxOn
\NewDocumentCommand{\addthinspace}{m}
 {
  \clist_use:nn { #1 } { \,, }
 }
\ExplSyntaxOff

答案2

如果您决定将列表放入,{...}则需要两个宏,因为 TeX{...}只能将宏封装的参数读取为不可分割的对象。外部宏可以将其作为另一个内部宏的参数,{...}而第二个宏可以读取由给定标记分隔的参数。这意味着:

% usage \innerproduct{a,b}
\def\innerproduct #1{\innerproductA #1\relax}
\def\innerproductA #1,#2\relax{\left\langle{#1}\,,{#2}\right\rangle}

如果您决定使用其他符号来表示您的参数,那么您就没有问题,并且您只能定义单个宏。例如:

% usage \innerproduct <a,b>
\def\innerproduct <#1,#2>{\left\langle{#1}\,,{#2}\right\rangle}

答案3

乍一看,使用两个命令来做一些相对简单的事情似乎有点愚蠢,但这种方式有其优势。有一个文档级命令,用户将使用它,并且它将始终以相同的方式使用,即在本例中提供由逗号分隔的两个项目的列表。然后,这个小列表被传递给编程层定义的内部命令,该命令实际上实现了所需的格式。文档级命令中隐藏了详细信息,这意味着可以修改实现,而不会更改命令在文档中的使用方式。

以下示例展示了使用 L3 编程层实现内积示例的一种方法。我假设使用的是最新的 TeX Live 发行版,并添加了注释,希望能够让大家理解。

% !TEX program = lualatexmk
% !TEX encoding = UTF-8 Unicode

\documentclass{article}

\ExplSyntaxOn
% Document level command
\NewDocumentCommand{\InnerProduct}{ m }
  {
    \__aubergine_innerproduct:n { #1 }
  }%
% Programming layer command.
% Define a new sequence.
\seq_new:N \l__aubergine_vectorarg_seq
% Define a new function that takes one argument, which
% is a sequence of two items separated by a comma.
\cs_new_protected:Npn \__aubergine_innerproduct:n #1
  {
    % Split the sequence into individual items delimited
    % by the comma.
    \seq_set_split:Nnn \l__aubergine_vectorarg_seq {,} { #1 }
    % Format the items one at a time between angle brackers
    % and again separated by a comma and a space.
    \langle \seq_use:Nn \l__aubergine_vectorarg_seq { \, , } \rangle
  }
\ExplSyntaxOff

\begin{document}
\( \InnerProduct{a,b} \)

\[
  \InnerProduct{c,d}
\]
\end{document}

MWE 输出

答案4

从根本上来说,TeX很多编程语言的局限性。因此,通常为了实现某些功能,强制的定义辅助命令来执行任务。

它对你来说是不可见的,但\NewDocumentCommand它自己,当像 那样被调用时\NewDocumentCommand\innerproduct,定义了(至少,我真的不记得细节了)两个命令,一个是它\innerproduct自己,一个有“特殊”名称\innerproduct code(直接访问这个命令并不简单,你需要一些 TeX 知识。)

(技术说明:您可以通过“按需”定义哈希表条目来减少哈希表条目的数量,但从根本上来说,这没有什么区别。)

无论如何,我认为你想要的只是让代码简洁。这可以通过像这样的辅助宏来实现...

\documentclass{article}

% ======== begin magic ========
\ExplSyntaxOn
% #1: the command, #2: the body
\cs_new_protected:Npn \NewDocumentCommandTwoCommaSeparatedArgs #1 #2 {
    \exp_args:Nc \__aubergine_ndccomma_aux:NNn {\cs_to_str:N #1 ~ private} #1 {#2}
}
% #1: the private control sequence, #2: the command, #3: the body
\cs_new_protected:Npn \__aubergine_ndccomma_aux:NNn #1 #2 #3 {
    \cs_new_protected:Npn #1 ##1 ##2 {#3}
    \NewDocumentCommand#2{>{\SplitArgument{1}{,}}m}{#1##1}
}
\ExplSyntaxOff
% ======== end magic ========

% then you can simply do this. It "looks like" only one command definition, but is actually at least *three*.
\NewDocumentCommandTwoCommaSeparatedArgs\innerproduct{\left\langle{#1}\,,{#2}\right\rangle}

\begin{document}

$\innerproduct{a, b}$

\end{document}

输出正如您所期望的。

相关内容