newcommand:不能包含宏作为参数

newcommand:不能包含宏作为参数

我觉得自己有点愚蠢,但是为什么我不能将宏放在我的参数中newcommand?为什么我的宏不能在环境\pra中工作align,而如果我手动编写扩展宏,它肯定可以工作?

我的宏(表示概率):

\newcommand*{\pr}[2][]{\ifthenelse{\equal{#1}{}}{\Pr[\,#2\,]}{\Pr_{#1}[\,#2\,]}}

这应该会产生类似这样的结果:

在此处输入图片描述

这有效:

\pr[b \leftarrow \{0,1\}]{a = 0 \mid b = 0} 

失败了:

\pr[\substack{a \leftarrow \{0,1\}}]{a = 0 \mid b = 0}

出现错误:

ERROR: Use of \\pr doesn't match its definition.

--- TeX said ---
\new@ifnextchar ...served@d = #1\def \reserved@a {
                                                  #2}\def \reserved@b {#3}\f...l.18 ...k{a \leftarrow \{0,1\}}]{a = 0 \mid b = 0}
                                                  \]

更奇怪的是,在一个等式中,以前起作用的宏align版本现在失败了,而如果我手动编写所有内容,它就可以起作用......\pr

谢谢!

梅威瑟:

\documentclass[]{article}

\usepackage{amsmath}
\usepackage{ifthen}
\setlength{\parindent}{0pt}

\newcommand*{\pr}[2][]{\ifthenelse{\equal{#1}{}}{\Pr[\,#2\,]}{\Pr_{#1}[\,#2\,]}}

\newcommand*{\pra}[2][]{\ifthenelse{\equal{#1}{}}{\Pr[\,#2\,]}{\Pr_{\substack{#1}}[\,#2\,]}}

\begin{document}
This works:
\[\pr{a = 0 \mid b = 0}\]
\[\pr[b \leftarrow \{0,1\}]{a = 0 \mid b = 0}\]
\[\Pr_{\substack{a \leftarrow \{0,1\}\\b \leftarrow \{0,1\}}} [a = 0 \mid b = 0]\]
This fails:
% \[\pr[\substack{a \leftarrow \{0,1\}}]{a = 0 \mid b = 0}\]
% \[\pr[\substack{a \leftarrow \{0,1\}\\b \leftarrow \{0,1\}}]{a = 0 \mid b = 0}\]

But if I put substack inside, it works:
\[\pra[a \leftarrow \{0,1\}]{a = 0 \mid b = 0}\]
\[\pra[a \leftarrow \{0,1\}\\b \leftarrow \{0,1\}]{a = 0 \mid b = 0}\]

Now, it's still stranger: if I put the full expression without my macro, it works inside an align:
\begin{align}
  \Pr_{\substack{a \leftarrow \{0,1\}\\b \leftarrow \{0,1\}}}[a = 0 \mid b = 0]
\end{align}
But if I use the macro that was used before, it fails:

% \begin{align}
%   \pra[a \leftarrow \{0,1\}\\b \leftarrow \{0,1\}]{a = 0 \mid b = 0}
% \end{align}

% even if I use protect:
%\begin{align}
%  \pr[\protect\substack{a \leftarrow \{0,1\}\\b \leftarrow \{0,1\}}]{a = 0 \mid b = 0}
%\end{align}

\end{document}

答案1

一般来说,你可以将宏作为参数,但你可能需要小心处理这些参数。并非所有宏都能同样好地处理所有输入。

\ifthenelse似乎不太喜欢像 这样的复杂怪物\substack。我认为\ifthenelse\equal测试试图扩展它所比较的​​字符串,这是错误的,因为\substack是不可扩展的。在这种情况下,在不可扩展的内容之前进行健康的\protect可能会有所帮助,但一段时间后可能会变得乏味。

我会\ifthenelse{\equal{#1}{}}etoolbox's来替换\ifblank{#1},它不会进行扩展,因此不需要额外的帮助来处理甚至像\substack这样复杂的东西。

\documentclass[]{article}
\usepackage{amsmath}
\usepackage{etoolbox}

\newcommand*{\pr}[2][]{%
  \ifblank{#1}
    {\Pr[\,#2\,]}
    {\Pr_{#1}[\,#2\,]}}

\begin{document}
\begin{align}
  \pr[\substack{a \leftarrow \{0,1\}\protect\\b \leftarrow \{0,1\}}]{a = 0 \mid b = 0}
\end{align}
\end{document}

事实上,\ifblank没有扩展其参数而 扩展\equal了,这意味着两个测试的行为存在差异。

比较

\documentclass[]{article}
\usepackage{amsmath}
\usepackage{etoolbox}
\usepackage{ifthen}

\newcommand*{\imblank}{}

\begin{document}
\ifthenelse{\equal{\imblank}{}}
  {T}
  {F}

\ifblank{\imblank}
  {T}
  {F}
\end{document}

答案2

这个\ifthenelse测试有点脆弱。有很多更好的方法来处理空的可选参数。

使用xparse参数类型 测试不出现的可选参数是可行的o。请参阅“简单定义”,我将其注释掉,因为可以有一个更好的定义,即在需要时使用\pr*而不是不同的命令进行插入\substack

\documentclass{article}

\usepackage{amsmath}
\usepackage{xparse}

%%% Easy version
%\NewDocumentCommand{\pr}{om}{%
%  \IfNoValueTF{#1}
%   {% no optional argument
%    \Pr[\,#2\,]%
%   }
%   {% optional argument is expressed
%    \Pr_{#1}[\,#2\,]%
%   }%
%}
%%% Better version
\NewDocumentCommand{\pr}{som}{%
  % * = use substack
  % #2 = optional
  % #3 = mandatory
  \Pr\IfValueT{#2}{_{\IfBooleanTF{#1}{\substack{#2}}{#2}}}[\,#3\,]
}

\begin{document}

\begin{gather*}
\pr{a = 0 \mid b = 0}
\\
\pr[b \leftarrow \{0,1\}]{a = 0 \mid b = 0}
\\
\pr*[a \leftarrow \{0,1\}\\b \leftarrow \{0,1\}]{a = 0 \mid b = 0}
\end{gather*}

\end{document}

会发生什么?如果可选参数没有出现,则\IfNoValueTF返回真分支,否则返回假分支。这与相反\IfValueTF。这里我们可以缩写为\IfValueT,因为当可选参数缺失时我们不需要做任何事情。

在这个条件文本中,我们使用了另一个条件:如果*在之后存在\pr\IfBooleanTF则返回 true 分支,并且可选参数被包围\substack。否则,将使用普通参数。

在此处输入图片描述

答案3

需要在可选参数[何时\protect使用]中。\substack\ifthenelse

\documentclass[]{article}

\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{ifthen}
\setlength{\parindent}{0pt}

\newcommand*{\pr}[2][]{\ifthenelse{\equal{#1}{}}{\Pr[\,#2\,]}{\Pr_{#1}[\,#2\,]}}

\newcommand*{\pra}[2][]{\ifthenelse{\equal{#1}{}}{\Pr[\,#2\,]}{\Pr_{\substack{#1}}[\,#2\,]}}

\begin{document}
This works:
\[\pr{a = 0 \mid b = 0}\]
\[\pr[b \leftarrow \{0,1\}]{a = 0 \mid b = 0}\]
\[\Pr_{\substack{a \leftarrow \{0,1\}\\b \leftarrow \{0,1\}}} [a = 0 \mid b = 0]\]
This [no longer] fails with \verb|\protect|:
 \[\pr[\protect\substack{a \leftarrow \{0,1\}}]{a = 0 \mid b = 0}\]
 \[\pr[\protect\substack{a \leftarrow \{0,1\}\\b \leftarrow \{0,1\}}]{a = 0 \mid b = 0}\]

But if I put substack inside, it works:
\[\pra[a \leftarrow \{0,1\}]{a = 0 \mid b = 0}\]
\[\pra[a \leftarrow \{0,1\}\\b \leftarrow \{0,1\}]{a = 0 \mid b = 0}\]

\end{document}

在此处输入图片描述

相关内容