nuevocomando: no se puede incluir macro como argumento

nuevocomando: no se puede incluir macro como argumento

Me siento un poco estúpido, pero ¿por qué no puedo poner macros dentro del argumento de mi newcommand? ¿Y por qué mi macro no puede \prafuncionar dentro del alignentorno, mientras que definitivamente funciona si escribo manualmente la macro expandida?

Mi macro (para denotar probabilidades):

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

Se supone que eso produce algo como esto:

ingrese la descripción de la imagen aquí

Esto funciona:

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

Esto falla:

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

con el error:

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

Y más extraño aún, dentro de una alignecuación, la versión \prde la macro que antes funcionaba ahora falla, mientras que si escribo todo manualmente funciona...

¡Gracias!

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}

Respuesta1

En general, puedes dar macros como argumentos, pero es posible que tengas que tener un poco de cuidado con lo que haces con esos argumentos. No todas las macros pueden manejar todas las entradas igualmente bien.

\ifthenelseNo parece estar muy contento con bestias complejas como \substack. Creo \ifthenelseque la \equalprueba intenta expandir las cadenas que compara, lo cual sale mal porque \substackno es expandible. En ese caso, una buena dosis de \protectcontenido no expandible puede ayudar, pero probablemente se vuelva tedioso después de un tiempo.

Lo reemplazaría \ifthenelse{\equal{#1}{}}con etoolbox's \ifblank{#1}, que no se expande y, por lo tanto, no necesita ayuda adicional para lidiar incluso con cosas complejas como \substackaquí.

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

El hecho de que \ifblankno amplíe su argumento aunque \equalsí significa que existen diferencias en el comportamiento de las dos pruebas.

Comparar

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

\newcommand*{\imblank}{}

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

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

Respuesta2

La \ifthenelseprueba es un poco frágil. Hay formas mucho mejores de lidiar con argumentos opcionales vacíos.

Con xparsela prueba de un argumento opcional que no aparece es posible con el tipo de argumento o. Vea la “definición fácil”, que comento porque es posible una aún mejor, usando \pr*en lugar de un comando diferente para insertar \substackcuando sea necesario.

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

¿Lo que sucede? Si el argumento opcional no aparece, \IfNoValueTFdevuelve la rama verdadera; en caso contrario, la rama falsa. Esto se invierte con \IfValueTF. Aquí podemos abreviar como \IfValueT, porque no necesitamos hacer nada cuando falta el argumento opcional.

Dentro de este texto condicional usamos otro condicional: si *está presente después de \pr, \IfBooleanTFdevuelve la rama verdadera y el argumento opcional está rodeado por \substack. De lo contrario, se utiliza el argumento simple.

ingrese la descripción de la imagen aquí

Respuesta3

Es necesario \protectincluir \substackun argumento opcional [cuando \ifthenelsese utiliza].

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

ingrese la descripción de la imagen aquí

información relacionada