Argomenti nominativi opzionali in Mathematica
-
06-07-2019 - |
Domanda
Qual è il modo migliore / canonico per definire una funzione con argomenti nominativi opzionali? Per renderlo concreto, creiamo una funzione foo
con argomenti denominati a
, b
e c
, che di default a 1, 2 e 3, rispettivamente. Per fare un confronto, ecco una versione di pippo
con argomenti posizionali:
foo[a_:1, b_:2, c_:3] := bar[a,b,c]
Ecco un esempio di input e output per la versione di argomenti denominati di foo
:
foo[] --> bar[1,2,3]
foo[b->7] --> bar[1,7,3]
foo[a->6, b->7, c->8] --> bar[6,7,8]
Ovviamente dovrebbe anche essere facile avere argomenti posizionali prima degli argomenti nominati.
Soluzione
Ho trovato il modo standard per farlo nella documentazione di 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]
Digitando " OptionValue " ogni volta è un po 'ingombrante. Per qualche motivo non puoi semplicemente creare un'abbreviazione globale come ov = OptionValue
ma puoi farlo:
foo[OptionsPattern[]] := Module[{ov},
ov[x___] := OptionValue[x];
bar[ov@a, ov@b, ov@c]]
O questo:
With[{ov = OptionValue},
foo[OptionsPattern[]] := bar[ov@a, ov@b, ov@c]
]
O questo:
$PreRead = ReplaceAll[#, "ov" -> "OptionValue"] &;
foo[OptionsPattern[]] := bar[ov@a, ov@b, ov@c]
Altri suggerimenti
Sì, OptionValue
può essere un po 'complicato perché si basa su un pezzo di magia in modo che
OptionValue [nome]
è equivalente aOptionValue [f, name]
, dovef
è la testa del lato sinistro di la regola di trasformazione in cui viene visualizzatoOptionValue [nome]
.
Lanciare un automatico
esplicito di solito fa il trucco, quindi nel tuo caso direi che la soluzione è:
Options[foo] = {a -> 1, b -> 2, c -> 3};
foo[OptionsPattern[]] :=
bar @@ (OptionValue[Automatic, #] &) /@ First /@ Options[foo]
A proposito, le opzioni erano da fare abbinando opta: ___? OptionQ
, e quindi trovando manualmente i valori delle opzioni come {a, b, c} /. Flatten [{ opta}]
. Il pattern check OptionQ
è ancora disponibile (anche se non documentato), ma l'approccio OptionValue
ha il vantaggio di ricevere avvisi per opzioni inesistenti (ad es. foo [ d- > 3]
). Questo sarebbe anche il caso della tua seconda risposta, ma non di quella che hai accettato.
Lancio questa possibile soluzione nel mix:
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]]
]
Mi piace per la sua morbidezza, ma non credo sia il modo standard. Qualche problema con farlo in questo modo?
PS, utilizza la seguente utile funzione di utilità:
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. *)