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.

È stato utile?

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 a OptionValue [f, name] , dove f è la testa del lato sinistro di la regola di trasformazione in cui viene visualizzato OptionValue [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.       *)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top