novo comando: não é possível incluir macro como argumento

novo comando: não é possível incluir macro como argumento

Eu me sinto um pouco estúpido, mas por que não consigo colocar macros dentro do argumento do meu newcommand? E por que minha macro não \prafunciona dentro do alignambiente, embora definitivamente funcione se eu apenas escrever manualmente a macro expandida?

Minha macro (para denotar probabilidades):

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

Isso deveria produzir algo assim:

insira a descrição da imagem aqui

Isso funciona:

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

Isso falha:

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

com o erro:

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}
                                                  \]

E ainda mais estranho, dentro de uma alignequação, a versão \prda macro que funcionava agora falha, enquanto se eu escrever tudo manualmente ela funciona...

Obrigado!

MWE:

\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}

Responder1

Em geral, você pode fornecer macros como argumentos, mas talvez seja necessário ter um pouco de cuidado com o que você faz com esses argumentos. Nem todas as macros conseguem lidar igualmente bem com todas as entradas.

\ifthenelsenão parece muito feliz com feras complexas como \substack. Acho que \ifthenelseo \equalteste de tenta expandir as strings que compara, o que dá errado porque \substacknão é expansível. Nesse caso, uma boa dose de \protectconteúdo não expansível pode ajudar, mas isso provavelmente se torna entediante depois de um tempo.

Eu substituiria \ifthenelse{\equal{#1}{}}por etoolbox's \ifblank{#1}, que não faz expansão e, portanto, não precisa de ajuda adicional para lidar até mesmo com coisas complexas como \substackaqui.

\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}

O fato de \ifblanknão expandir seu argumento enquanto \equalo faz significa que há diferenças no comportamento dos dois testes.

Comparar

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

\newcommand*{\imblank}{}

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

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

Responder2

O \ifthenelseteste é um pouco frágil. Existem maneiras muito melhores de lidar com argumentos opcionais vazios.

Com xparseo teste para um argumento opcional que não aparece é possível com o argumento type o. Veja a “definição fácil”, que comento porque é possível uma ainda melhor, usando \pr*em vez de um comando diferente para inserir \substackquando necessário.

\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}

O que acontece? Se o argumento opcional não aparecer, \IfNoValueTFretorna o ramo verdadeiro, caso contrário, o ramo falso. Isso é revertido com \IfValueTF. Aqui podemos abreviar para \IfValueT, porque não precisamos fazer nada quando falta o argumento opcional.

Dentro deste texto condicional usamos outra condicional: if *está presente depois de \pr, \IfBooleanTFretorna o ramo verdadeiro e o argumento opcional é cercado por \substack. Caso contrário, o argumento simples é usado.

insira a descrição da imagem aqui

Responder3

Precisa de \protectum \substackargumento opcional [quando \ifthenelseestá sendo usado].

\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}

insira a descrição da imagem aqui

informação relacionada