2009-10-23 2 views
10

Qual è il modo migliore/canonico per definire una funzione con argomenti denominati facoltativi? Per renderlo concreto, creiamo una funzione foo con argomenti denominati a, b e c, che per impostazione predefinita sono 1, 2 e 3, rispettivamente. Per confronto, ecco una versione di foo con argomenti posizionali:Argomenti opzionali denominati in Mathematica

foo[a_:1, b_:2, c_:3] := bar[a,b,c] 

Ecco input di esempio e di uscita per la versione-argomenti con nome 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] 

Dovrebbe naturalmente anche essere facile avere argomenti posizionali prima degli argomenti con nome.

+0

Vedere anche: http: // stackoverflow.it/questions/4682742/optional-named-arguments-senza-wrapping-them-all-in-optionvalue – dreeves

risposta

10

Ho trovato il modo standard per farlo nella documentazione 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]] 

Digitando "OptionValue" ogni volta è una poco ingombrante. Per qualche motivo non si può semplicemente fare una sigla globale come ov = OptionValue, ma si può fare questo:

foo[OptionsPattern[]] := Module[{ov}, 
    ov[x___] := OptionValue[x]; 
    bar[[email protected], [email protected], [email protected]]] 

O questo:

With[{ov = OptionValue}, 
    foo[OptionsPattern[]] := bar[[email protected], [email protected], [email protected]] 
] 

O questo:

$PreRead = ReplaceAll[#, "ov" -> "OptionValue"] &; 

foo[OptionsPattern[]] := bar[[email protected], [email protected], [email protected]] 
+0

Informazioni sulla digitazione di OptionValue: In questo caso si potrebbe dire 'In [32]: = OptionValue/@ bar [a, b, c] Out [32] = bar [OptionValue [a], OptionValue [b], OptionValue [c]] ' –

+0

@dreeves C'è una forma più concisa dell'ultimo blocco di codice usando' With' piuttosto che ' module'. Posso modificare la tua risposta per aggiungere questo? –

+0

@Sjoerd divertente, il tuo commento non era lì quando ho caricato questa pagina. Immagino che tu stia leggendo anche questi vecchi post. –

2

mi butto questa possibile soluzione nel mix:

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]]] 
] 

mi piace per la sua concisione, ma non credo che sia il modo standard. Qualche scusa per averlo fatto in quel modo?

PS, si utilizza la seguente funzione di utilità a portata di mano:

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.  *) 
4

Sì, OptionValue può essere un po 'complicato perché si basa su un pezzo di magia in modo che

OptionValue[name] equivale a OptionValue[f,name], dove f è la testa del lato sinistro della regola di trasformazione in cui appare OptionValue[name].

Gettare in un esplicito Automatic di solito fa il trucco, così nel tuo caso direi che la soluzione è:

Options[foo] = {a -> 1, b -> 2, c -> 3}; 
foo[OptionsPattern[]] := 
    bar @@ (OptionValue[Automatic, #] &) /@ First /@ Options[foo] 

Tra l'altro, opzioni utilizzate per essere fatto facendo corrispondere a opts:___?OptionQ, e quindi trovare i valori delle opzioni manualmente come {a,b,c}/.Flatten[{opts}]. Il controllo del modello OptionQ è ancora in circolazione (anche se non è documentato), ma l'approccio OptionValue ha il vantaggio di ricevere avvertimenti per le opzioni non esistenti (ad esempio foo[d->3]). Questo sarebbe anche il caso della tua seconda risposta, ma non per quella che hai accettato.