
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 \pra
funciona dentro do align
ambiente, 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:
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 align
equação, a versão \pr
da 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.
\ifthenelse
não parece muito feliz com feras complexas como \substack
. Acho que \ifthenelse
o \equal
teste de tenta expandir as strings que compara, o que dá errado porque \substack
não é expansível. Nesse caso, uma boa dose de \protect
conteú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 \substack
aqui.
\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 \ifblank
não expandir seu argumento enquanto \equal
o 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 \ifthenelse
teste é um pouco frágil. Existem maneiras muito melhores de lidar com argumentos opcionais vazios.
Com xparse
o 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 \substack
quando 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, \IfNoValueTF
retorna 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
, \IfBooleanTF
retorna o ramo verdadeiro e o argumento opcional é cercado por \substack
. Caso contrário, o argumento simples é usado.
Responder3
Precisa de \protect
um \substack
argumento opcional [quando \ifthenelse
está 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}