我觉得自己有点愚蠢,但是为什么我不能将宏放在我的参数中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}