
少しバカみたいに感じるのですが、なぜマクロを の引数内に入れることができないのでしょうか? また、拡張マクロを手動で記述すれば確実に機能するのに、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
ありがとう!
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}
答え1
一般的に、マクロを引数として与えることができますが、それらの引数をどのように扱うかについては少し注意する必要があります。すべてのマクロがすべての入力を同じようにうまく処理できるわけではありません。
\ifthenelse
は、 のような複雑なものにはあまり向いていないようです\substack
。\ifthenelse
の\equal
テストは比較する文字列を展開しようとしますが、 は\substack
展開できないため、うまくいきません。その場合、\protect
展開できないコンテンツの前に を適切に行うことで解決できるかもしれませんが、しばらくすると面倒になるでしょう。
私は\ifthenelse{\equal{#1}{}}
を に置き換えます。これは展開を行わないため、ここでのような複雑なものでも処理するために追加の支援を必要としません。etoolbox
\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
、2 つのテストの動作に違いがあることを意味します。
比較する
\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
は true ブランチを返し、そうでない場合は false ブランチを返します。 これは で逆になります。 ここでは、オプション引数がない場合は何もする必要がないため、\IfValueTF
と省略できます。\IfValueT
この条件文内では、別の条件文を使用します。*
が の後に存在する場合\pr
、\IfBooleanTF
は true ブランチを返し、オプションの引数は で囲まれます\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}