13

使用可选命名参数定义函数的最佳/规范方法是什么?为了使其具体化,让我们创建一个foo具有命名参数ab和的函数c,它们的默认值分别为 1、2 和 3。为了比较,这是一个foo带有位置参数的版本:

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

这是命名参数版本的示例输入和输出foo

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

当然,在命名参数之前也应该很容易有位置参数。

4

3 回答 3

12

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

每次都输入“OptionValue”有点麻烦。出于某种原因,您不能只使用全局缩写,ov = OptionValue但您可以这样做:

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

或这个:

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

或这个:

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

foo[OptionsPattern[]] := bar[ov@a, ov@b, ov@c]
于 2009-10-23T21:53:15.307 回答
6

是的,OptionValue可能有点棘手,因为它依赖于一个魔法,所以

OptionValue[name]等价于OptionValue[f,name],其中出现f的变换规则左侧的头部OptionValue[name]

抛出一个明确的Automatic通常是诀窍,所以在你的情况下,我会说解决方案是:

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

顺便说一句,过去的选项是通过匹配来完成的opts:___?OptionQ,然后手动查找选项值作为{a,b,c}/.Flatten[{opts}]。模式检查OptionQ仍然存在(尽管没有记录),但该OptionValue方法的优点是您会收到不存在选项的警告(例如foo[d->3])。您的第二次回复也是如此,但您接受的回复并非如此。

于 2010-02-19T06:40:22.300 回答
1

我将把这个可能的解决方案混合起来:

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

我喜欢它的简洁性,但我不认为这是标准的方式。这样做有什么问题吗?

PS,它使用以下方便的实用功能:

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.       *)
于 2009-10-23T20:58:40.030 回答