
Ich komme mir ein bisschen dumm vor, aber warum kann ich keine Makros in das Argument meines einfügen newcommand
? Und warum kann mein Makro nicht \pra
innerhalb der align
Umgebung funktionieren, obwohl es definitiv funktioniert, wenn ich das erweiterte Makro einfach manuell schreibe?
Mein Makro (zur Angabe von Wahrscheinlichkeiten):
\newcommand*{\pr}[2][]{\ifthenelse{\equal{#1}{}}{\Pr[\,#2\,]}{\Pr_{#1}[\,#2\,]}}
Das sollte ungefähr Folgendes ergeben:
Das funktioniert:
\pr[b \leftarrow \{0,1\}]{a = 0 \mid b = 0}
Dies schlägt fehl:
\pr[\substack{a \leftarrow \{0,1\}}]{a = 0 \mid b = 0}
mit dem Fehler:
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}
\]
Und noch seltsamer: Innerhalb einer align
Gleichung funktioniert jetzt nicht mehr die Version \pr
des Makros, die vorher funktioniert hat, während es funktioniert, wenn ich alles manuell schreibe ...
Danke!
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}
Antwort1
Im Allgemeinen können Sie Makros als Argumente angeben, aber Sie müssen bei der Verwendung dieser Argumente etwas vorsichtig sein. Nicht alle Makros können mit allen Eingaben gleich gut umgehen.
\ifthenelse
scheint mit komplexen Monstern wie nicht allzu glücklich zu sein \substack
. Ich glaube, \ifthenelse
der Test von \equal
versucht, die verglichenen Zeichenfolgen zu erweitern, was schiefgeht, weil \substack
nicht erweiterbar ist. In diesem Fall kann eine ordentliche Dosis von \protect
vor nicht erweiterbarem Inhalt helfen, aber das wird nach einer Weile wahrscheinlich langweilig.
Ich würde es \ifthenelse{\equal{#1}{}}
durch etoolbox
's ersetzen \ifblank{#1}
, das keine Erweiterung vornimmt und daher keine weitere Hilfe benötigt, um selbst mit komplexen Dingen wie \substack
hier fertig zu werden.
\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}
Die Tatsache, dass \ifblank
sein Argument nicht erweitert, während \equal
dies der Fall ist, bedeutet, dass es Unterschiede im Verhalten der beiden Tests gibt.
Vergleichen
\documentclass[]{article}
\usepackage{amsmath}
\usepackage{etoolbox}
\usepackage{ifthen}
\newcommand*{\imblank}{}
\begin{document}
\ifthenelse{\equal{\imblank}{}}
{T}
{F}
\ifblank{\imblank}
{T}
{F}
\end{document}
Antwort2
Der \ifthenelse
Test ist etwas fragil. Es gibt viel bessere Möglichkeiten, mit leeren optionalen Argumenten umzugehen.
Mit xparse
dem Argumenttyp ist der Test auf ein nicht erscheinendes optionales Argument möglich o
. Siehe die „einfache Definition“, die ich auskommentiere, weil eine noch bessere möglich ist, indem man \pr*
anstelle eines anderen Befehls verwendet, der \substack
bei Bedarf eingefügt wird.
\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}
Was passiert? Wenn das optionale Argument nicht vorkommt, \IfNoValueTF
gibt es den True-Zweig zurück, andernfalls den False-Zweig. Umgekehrt verhält es sich mit \IfValueTF
. Hier können wir mit abkürzen \IfValueT
, da wir bei fehlendem optionalen Argument nichts tun müssen.
Innerhalb dieses bedingten Textes verwenden wir eine weitere Bedingung: Wenn *
nach steht \pr
, \IfBooleanTF
wird der wahre Zweig zurückgegeben und das optionale Argument ist von umgeben \substack
. Andernfalls wird das einfache Argument verwendet.
Antwort3
Es muss ein optionales Argument enthalten sein [wenn \protect
es verwendet wird].\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}