Mathematica 中的可选命名参数

发布于 2024-08-09 07:36:26 字数 475 浏览 2 评论 0原文

使用可选命名参数定义函数的最佳/规范方法是什么?为了使其具体化,让我们创建一个带有命名参数 abc 的函数 foo,默认情况下分别为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]

它当然也应该很容易拥有命名参数之前的位置参数。

What's the best/canonical way to define a function with optional named arguments? To make it concrete, let's create a function foo with named arguments a, b, and c, which default to 1, 2, and 3, respectively. For comparison, here's a version of foo with positional arguments:

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

Here is sample input and output for the named-arguments version of foo:

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

It should of course also be easy to have positional arguments before the named arguments.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

软的没边 2024-08-16 07:36:26

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

I found the standard way to do it in the Mathematica documentation: 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]

Typing "OptionValue" every time is a little cumbersome. For some reason you can't just make a global abbreviation like ov = OptionValue but you can do this:

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

Or this:

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

Or this:

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

foo[OptionsPattern[]] := bar[ov@a, ov@b, ov@c]
沩ん囻菔务 2024-08-16 07:36:26

是的,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< 来完成的/code>,然后手动查找选项值 {a,b,c}/.Flatten[{opts}]。模式检查 OptionQ 仍然存在(尽管没有记录),但是 OptionValue 方法的优点是您会收到不存在选项的警告(例如 foo[ d->3])。您的第二个回复也是如此,但您已接受的回复则不然。

Yes, OptionValue can be a bit tricky because is relies on a piece of magic so that

OptionValue[name] is equivalent to OptionValue[f,name], where f is the head of the left-hand side of the transformation rule in which OptionValue[name] appears.

Throwing in an explicit Automatic usually does the trick, so in your case I would say that the solution is:

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

By the way, options used to be done by matching to opts:___?OptionQ, and then finding option values manually as {a,b,c}/.Flatten[{opts}]. The pattern check OptionQ is still around (although not documented), but the OptionValue approach has the advantage that you get warnings for non-existing options (e.g. foo[d->3]). This would also be the case for your second response, but not for the one you have accepted.

轻许诺言 2024-08-16 07:36:26

我将把这个可能的解决方案加入其中:

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.       *)

I'll throw this possible solution into the mix:

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

I like it for its terseness but I don't think it's the standard way. Any gotchas with doing it that way?

PS, it uses the following handy utility function:

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.       *)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文