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может помочь здоровая does of до нерасширяемого содержимого, но это, вероятно, станет утомительным через некоторое время.

Я бы заменил \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возвращает истинную ветвь, а необязательный аргумент окружен \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}

введите описание изображения здесь

Связанный контент