2009-10-23 2 views
10

Was ist der beste/kanonische Weg, um eine Funktion mit optionalen benannten Argumenten zu definieren? Um es konkreter zu gestalten, erstellen wir eine Funktion foo mit den genannten Argumenten a, b und c, die standardmäßig auf 1, 2 bzw. 3 festgelegt sind. Zum Vergleich ist hier eine Version von foo mit Positionsargumenten:Optional benannte Argumente in Mathematica

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

Hier Probe Eingang und Ausgang für die benannte Argumente Version von foo:

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

Es sollte natürlich auch leicht zu haben Positionsargumente vor den benannten Argumenten.

+0

Siehe auch: http: // stackoverflow.com/questions/4682742/optional-named-arguments-ohne-wrapping-sie-alle-in-optionvalue – dreeves

Antwort

10

ich den Standard-Weg fand sie in der Mathematica-Dokumentation zu tun: 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]] 

Typing "Option" jedes Mal ein wenig umständlich. Aus irgendeinem Grund kann man nicht nur eine globale Abkürzung wie ov = OptionValue machen, aber Sie können dies tun:

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

Oder diese:

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

Oder diese:

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

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

Über umständliche Typisierung von OptionValue: In diesem Fall könnten Sie sagen: In [32]: = OptionValue/@ bar [a, b, c] Out [32] = Balken [OptionValue [a], OptionValue [b], OptionValue [c]] ' –

+0

@dreeves Es gibt eine prägnantere Form des letzten Codeblocks mit' With' anstelle von ' Modul'. Darf ich Ihre Antwort bearbeiten, um sie anzufügen? –

+0

@Sjoerd lustig, Ihr Kommentar war nicht da, als ich diese Seite geladen habe. Ich schätze, du liest auch diese alten Beiträge. –

2

Ich würde diese mögliche Lösung in den Mix werfen:

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

ich es für seine Prägnanz mögen, aber ich glaube nicht, dass der normale Weg ist. Irgendwelche Schwierigkeiten, es so zu machen?

PS, verwendet es die folgenden praktischen Nutzenfunktion:

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

Ja, OptionValue kann ein bisschen schwierig sein, weil es sich auf ein Stück Magie verlässt, so dass

OptionValue[name] entspricht OptionValue[f,name], wobei f der Kopf der linken Seite der Transformationsregel ist, in der OptionValue[name] erscheint.

in einer expliziten Automatic Werfen in der Regel funktioniert der Trick, so in Ihrem Fall würde ich sagen, dass die Lösung ist:

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

By the way, Optionen verwendet durch Anpassung an opts:___?OptionQ getan werden, und Dann finden Sie die Optionswerte manuell unter {a,b,c}/.Flatten[{opts}]. Die Musterprüfung OptionQ ist immer noch (obwohl nicht dokumentiert), aber die OptionValue Methode hat den Vorteil, dass Sie Warnungen für nicht vorhandene Optionen erhalten (z. B. foo[d->3]). Dies gilt auch für Ihre zweite Antwort, jedoch nicht für die, die Sie akzeptiert haben.