Pergunta

O que é a melhor maneira / canônica para definir uma função com argumentos opcionais nomeadas? Para torná-lo concreto, vamos criar um foo função com argumentos nomeados a, b e c, que padrão para 1, 2 e 3, respectivamente. Para efeito de comparação, aqui está uma versão do foo com argumentos posicionais:

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

Aqui é a entrada de amostra e de saída para a versão nomeadas-argumentos 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]

Deve também, naturalmente, ser fácil ter argumentos posicionais antes dos argumentos nomeados.

Foi útil?

Solução

Eu encontrei a maneira padrão de fazê-lo na documentação do Mathematica: http: // referência .wolfram.com / mathematica / tutorial / SettingUpFunctionsWithOptionalArguments.html

Options[foo] = {a->1, b->2, c->3};  (* defaults *)
foo[OptionsPattern[]] := bar[OptionValue@a, OptionValue@b, OptionValue@c]

Typing "OptionValue" cada vez é um pouco complicado. Por alguma razão, você não pode simplesmente fazer uma abreviatura global como ov = OptionValue mas você pode fazer isso:

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

Ou este:

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

Ou este:

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

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

Outras dicas

Sim, OptionValue pode ser uma causa complicada bit é baseia-se em um pedaço de magia para que

OptionValue[name] é equivalente a OptionValue[f,name], onde f é a cabeça do lado esquerdo da regra de transformação em que aparece OptionValue[name].

Jogando em uma Automatic explícita normalmente faz o truque, então no seu caso, eu diria que a solução é a seguinte:

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

A propósito, opções costumava ser feito por correspondência para opts:___?OptionQ, e em seguida, encontrar os valores de opção manualmente como {a,b,c}/.Flatten[{opts}]. O OptionQ verificação padrão ainda está por aí (embora não documentado), mas a abordagem OptionValue tem a vantagem de que você obtenha avisos para opções não-existente (por exemplo foo[d->3]). Este também seria o caso de sua segunda resposta, mas não para o que você aceitou.

Vou jogar esta solução possível para a mistura:

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

Eu gosto pela sua concisão, mas eu não acho que é a maneira padrão. Quaisquer pegadinhas com fazê-lo dessa maneira?

PS, ele usa a seguinte função utilidade acessível:

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top