Pregunta

¿Cuál es la mejor manera / canónica de definir una función con argumentos con nombre opcionales? Para hacerlo concreto, vamos a crear una función foo con argumentos con nombre a , b y c , que por defecto a 1, 2 y 3, respectivamente. A modo de comparación, aquí hay una versión de foo con argumentos posicionales:

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

Aquí hay una entrada y salida de muestra para la versión de argumentos nombrados 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]

Por supuesto, también debería ser fácil tener argumentos posicionales antes de los argumentos nombrados.

¿Fue útil?

Solución

Encontré la forma estándar de hacerlo en la documentación de 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]

Escribiendo " OptionValue " Cada vez es un poco engorroso. Por alguna razón, no puedes simplemente hacer una abreviatura global como ov = OptionValue pero puedes hacer esto:

foo[OptionsPattern[]] := Module[{ov},
  ov[x___] := OptionValue[x];
  bar[ov@a, ov@b, ov@c]]

O esto:

With[{ov = OptionValue},
  foo[OptionsPattern[]] := bar[ov@a, ov@b, ov@c]
]

O esto:

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

foo[OptionsPattern[]] := bar[ov@a, ov@b, ov@c]

Otros consejos

Sí, OptionValue puede ser un poco complicado porque se basa en un pedazo de magia para que

  

OptionValue [nombre] es equivalente a OptionValue [f, nombre] , donde f es la cabecera del lado izquierdo de la regla de transformación en la que aparece OptionValue [nombre] .

Lanzar un código automático explícito generalmente funciona, por lo que en su caso, diría que la solución es:

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

Por cierto, las opciones se hacían coincidiendo con las opciones de : ___? OptionQ , y luego encontrando los valores de las opciones manualmente como {a, b, c} /. Aplanar [{ opta}] . La verificación de patrón OptionQ todavía está presente (aunque no está documentada), pero el enfoque OptionValue tiene la ventaja de que recibe advertencias para opciones no existentes (por ejemplo, foo [ d- > 3] ). Este también sería el caso para su segunda respuesta, pero no para la que ha aceptado.

Pondré esta solución posible en la mezcla:

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

Me gusta por su terseness pero no creo que sea la forma estándar. ¿Alguna trampa de hacerlo de esa manera?

PS, utiliza la siguiente función de utilidad práctica:

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.       *)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top