いくつかの回答は、オプションを使用する古い方法と新しい方法のさまざまな側面を強調していますが、いくつかの追加の観察を行いたいと思います。新しい構成は、グローバルオプションOptionValue
のリストを調べて、渡されたオプションが関数に認識されていることを確認するため、OptionsPattern
よりも安全性が高くなります。ただし、古いものは、標準のパターンマッチングのみに基づいており、グローバルプロパティのいずれにも直接関連していないため、理解しやすいようです。これらの構造のいずれかによって提供されるこの追加の安全性が必要かどうかはあなた次第ですが、特に大規模なプロジェクトでは、ほとんどの人がそれを役立つと思うと思います。OptionQ
OptionValue
OptionQ
これらの型チェックが本当に役立つ理由の1つは、オプションがチェーンのような方法で関数によってパラメーターとして渡されたり、フィルター処理されたりすることが多いためです。そのため、このようなチェックがないと、パターンマッチングエラーの一部をキャッチするのが非常に困難になります。それらの起源の場所から「遠く」に害を引き起こしているでしょう。
コア言語に関しては、OptionValue
-OptionsPattern
構文はパターンマッチャーへの追加であり、おそらくそのすべての機能の中で最も「魔法のような」ものです。オプションをルールの特殊なケースと見なすことができる限り、意味的には必要ありませんでした。さらに、OptionValue
パターンマッチングをOptions[symbol]
グローバルプロパティに接続します。したがって、言語の純粋さを主張する場合、ルールはopts___?OptionQ
理解しやすいように見えます。これを理解するために、標準のルール置換セマンティクス以外は何も必要ありません。
f[a_, b_, opts___?OptionQ] := Print[someOption/.Flatten[{opts}]/.Options[f]]
OptionQ
(述語は、Mathematicaの古いバージョンのオプションを認識するように特別に設計されていることを思い出します)、これは:
f[a_, b_, opts:OptionsPattern[]] := Print[OptionValue[someOption]]
かなり魔法のように見えます。Trace
を使用して、の短い形式がより長い形式に評価されることを確認すると、少し明確になりますOptionValue
が、それが囲んでいる関数名を自動的に決定するという事実は依然として注目に値します。
OptionsPattern
パターンランゲージの一部であることの結果はさらにいくつかあります。1つは、@Sashaによって議論された速度の改善です。ただし、速度の問題はしばしば強調されすぎており(これは彼の観察を損なうものではありません)、オプションのある関数は特に非レベルの関数である可能性が高いため、これは特に当てはまると思います。計算時間のほとんどが費やされる些細な本体。
もう1つの興味深い違いは、引数を保持する関数にオプションを渡す必要がある場合です。次の例を考えてみましょう。
ClearAll[f, ff, fff, a, b, c, d];
Options[f] = Options[ff] = {a -> 0, c -> 0};
SetAttributes[{f, ff}, HoldAll];
f[x_, y_, opts___?OptionQ] :=
{{"Parameters:", {HoldForm[x], HoldForm[y]}}, {" options: ", {opts}}};
ff[x_, y_, opts : OptionsPattern[]] :=
{{"Parameters:", {HoldForm[x], HoldForm[y]}}, {" options: ", {opts}}};
これで結構です:
In[199]:= f[Print["*"],Print["**"],a->b,c->d]
Out[199]= {{Parameters:,{Print[*],Print[**]}},{ options: ,{a->b,c->d}}}
しかし、ここOptionQ
では、パターンマッチングプロセスの一部として、ベースの関数が評価をリークします。
In[200]:= f[Print["*"],Print["**"],Print["***"],a->b,c->d]
During evaluation of In[200]:= ***
Out[200]= f[Print[*],Print[**],Print[***],a->b,c->d]
これは完全に些細なことではありません。何が起こるかというと、パターンマッチャーは、一致または不一致の事実を確立するために、引数を保持していないため、Print
の評価の一部として3番目のを評価する必要があります。評価リークを回避するには、の代わりにを使用する必要があります。一致の事実は純粋に構文的に確立できるため、この問題は発生しません。OptionQ
OptionQ
Function[opt,OptionQ[Unevaluated[opt]],HoldAll]
OptionQ
OptionsPattern
In[201]:= ff[Print["*"],Print["**"],a->b,c->d]
Out[201]= {{Parameters:,{Print[*],Print[**]}},{ options: ,{a->b,c->d}}}
In[202]:= ff[Print["*"],Print["**"],Print["***"],a->b,c->d]
Out[202]= ff[Print[*],Print[**],Print[***],a->b,c->d]
つまり、要約すると、ある方法を別の方法から選択することは、主に好みの問題だと思います。それぞれが生産的に使用でき、また、それぞれが悪用される可能性があります。安全性が高いため、新しい方法を使用する傾向がありますが、古い方法の方が意味的に理解しやすい一方で、驚くようなコーナーケースがいくつか存在することを排除しません。これは、C-C ++の比較に似ています(これが適切な場合):自動化と(おそらく)安全性と単純さと純粋さ。私の2セント。