新しいコマンド: マクロを引数として含めることはできません

新しいコマンド: マクロを引数として含めることはできません

少しバカみたいに感じるのですが、なぜマクロを の引数内に入れることができないのでしょうか? また、拡張マクロを手動で記述すれば確実に機能するのに、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}

ここに画像の説明を入力してください

関連情報