Необязательные именованные аргументы в Mathematica
Какой лучший/канонический способ определить функцию с необязательными именованными аргументами? Чтобы сделать это конкретным, создайте функцию foo
с именованными аргументами a
, b
и c
, которые по умолчанию равны 1, 2 и 3 соответственно. Для сравнения здесь версия foo
с позиционными аргументами:
foo[a_:1, b_:2, c_:3] := bar[a,b,c]
Вот пример ввода и вывода для версии named-arguments foo
:
foo[] --> bar[1,2,3]
foo[b->7] --> bar[1,7,3]
foo[a->6, b->7, c->8] --> bar[6,7,8]
Конечно, также должно быть легко иметь позиционные аргументы перед именованными аргументами.
Ответы
Ответ 1
Я нашел стандартный способ сделать это в документации Mathematica: http://reference.wolfram.com/mathematica/tutorial/SettingUpFunctionsWithOptionalArguments.html
Options[foo] = {a->1, b->2, c->3}; (* defaults *)
foo[OptionsPattern[]] := bar[[email protected], [email protected], [email protected]]
Ввод "OptionValue" каждый раз немного громоздкий. По какой-то причине вы не можете просто сделать глобальную аббревиатуру, например ov = OptionValue
, но вы можете сделать это:
foo[OptionsPattern[]] := Module[{ov},
ov[x___] := OptionValue[x];
bar[[email protected], [email protected], [email protected]]]
Или это:
With[{ov = OptionValue},
foo[OptionsPattern[]] := bar[[email protected], [email protected], [email protected]]
]
Или это:
$PreRead = ReplaceAll[#, "ov" -> "OptionValue"] &;
foo[OptionsPattern[]] := bar[[email protected], [email protected], [email protected]]
Ответ 2
Да, OptionValue
может быть немного сложнее, потому что полагается на кусок магии, чтобы
OptionValue[name]
эквивалентно OptionValue[f,name]
, где f
- глава левой части правила преобразования, в котором появляется OptionValue[name]
.
Throwing в явном Automatic
обычно делает трюк, поэтому в вашем случае я бы сказал, что решение:
Options[foo] = {a -> 1, b -> 2, c -> 3};
foo[OptionsPattern[]] :=
bar @@ (OptionValue[Automatic, #] &) /@ First /@ Options[foo]
Кстати, параметры выполнялись путем сопоставления с opts:___?OptionQ
, а затем вручную определяли значения параметров как {a,b,c}/.Flatten[{opts}]
. Проверка шаблона OptionQ
все еще существует (хотя и не документирована), но подход OptionValue
имеет то преимущество, что вы получаете предупреждения о несуществующих опциях (например, foo[d->3]
). Это также будет иметь место для вашего второго ответа, но не для того, который вы приняли.
Ответ 3
Я поставлю это возможное решение в микс:
foo[opts___Rule] := Module[{f},
[email protected] = 1; (* defaults... *)
[email protected] = 2;
[email protected] = 3;
each[a_->v_, {opts}, [email protected] = v];
Return[bar[[email protected], [email protected], [email protected]]]
]
Мне это нравится, но я не думаю, что это стандартный способ. Любые ошибки с этим способом?
PS, он использует следующую удобную служебную функцию:
SetAttributes[each, HoldAll]; (* each[pattern, list, body] *)
each[pat_, lst_, bod_] := (* converts pattern to body for *)
Scan[Replace[#, pat:>bod]&, [email protected]] (* each element of list. *)