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