2009-10-23 8 views
10

Quelle est la meilleure façon/canonique de définir une fonction avec des arguments nommés facultatifs? Pour le rendre concret, créons une fonction foo avec les arguments nommés a, b, et c, qui par défaut sont 1, 2 et 3, respectivement. À titre de comparaison, voici une version de foo avec des arguments de position:Arguments nommés facultatifs dans Mathematica

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

Voici entrée échantillon et sortie pour la version nommée arguments de foo:

foo[]     --> bar[1,2,3] 
foo[b->7]    --> bar[1,7,3] 
foo[a->6, b->7, c->8] --> bar[6,7,8] 

Il faut bien sûr aussi facile d'avoir arguments de position avant les arguments nommés.

+0

Voir aussi: http: // stackoverflow.com/questions/4682742/optional-named-arguments-sans-wrapping-them-all-in-optionvalue – dreeves

Répondre

10

J'ai trouvé le moyen standard pour le faire dans la documentation 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]] 

Si vous tapez "OptionValue" à chaque fois est peu encombrant. Pour une raison quelconque vous ne pouvez pas faire une abréviation mondiale comme ov = OptionValue mais vous pouvez le faire:

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

Ou ceci:

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

Ou ceci:

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

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

A propos de la saisie fastidieuse de OptionValue: Dans ce cas, vous pouvez dire 'In [32]: = OptionValue/@ bar [a, Out [32] = bar [OptionValue [a], OptionValue [b], OptionValue [c]] ' –

+0

@dreeves Il existe une forme plus concise du dernier bloc de code utilisant' With' plutôt que ' Module'. Puis-je modifier votre réponse pour l'ajouter? –

+0

@Sjoerd drôle, votre commentaire n'était pas là quand j'ai chargé cette page. Je suppose que vous lisez ces vieux messages aussi. –

2

Je jetterai cette solution dans le mélange:

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

Je l'aime pour son laconisme, mais je ne pense pas que c'est la façon standard. Est-ce qu'il y a des trucs avec ça?

PS, il utilise la fonction utilitaire pratique suivante:

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

Oui, OptionValue peut être un peu difficile parce que repose sur un morceau de magie afin que

OptionValue[name] est équivalent à OptionValue[f,name], où f est la tête du côté gauche de la règle de transformation dans laquelle OptionValue[name] apparaît.

Lancer dans un Automatic explicite fait habituellement le tour, donc dans votre cas, je dirais que la solution est:

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

Par ailleurs, les options utilisées pour faire en faisant correspondre à opts:___?OptionQ, et puis en recherchant manuellement les valeurs de l'option {a,b,c}/.Flatten[{opts}]. La vérification de modèle OptionQ est toujours présente (bien que non documentée), mais l'approche OptionValue présente l'avantage d'obtenir des avertissements pour les options inexistantes (par exemple, foo[d->3]). Ce serait également le cas pour votre deuxième réponse, mais pas pour celle que vous avez acceptée.