可选的命名参数,无需将它们全部包装在“OptionValue"中; [英] Optional named arguments without wrapping them all in "OptionValue"

查看:23
本文介绍了可选的命名参数,无需将它们全部包装在“OptionValue"中;的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个带有可选命名参数的函数,但我坚持用它们朴素的名字来引用这些参数.

Suppose I have a function with optional named arguments but I insist on referring to the arguments by their unadorned names.

考虑这个将两个命名参数 a 和 b 相加的函数:

Consider this function that adds its two named arguments, a and b:

Options[f] = {a->0, b->0};  (* The default values. *)
f[OptionsPattern[]] := 
  OptionValue[a] + OptionValue[b]

如何编写该函数的一个版本,其中最后一行被简单地替换为 a+b?(想象一下,a+b 是一大堆代码.)

How can I write a version of that function where that last line is replaced with simply a+b? (Imagine that that a+b is a whole slew of code.)

以下问题的答案显示了如何缩写 OptionValue(说起来容易做起来难),但没有说明如何完全摆脱它:Mathematica 中的可选命名参数

The answers to the following question show how to abbreviate OptionValue (easier said than done) but not how to get rid of it altogether: Optional named arguments in Mathematica

哲学附录:似乎如果 Mathematica 将使用 OptionsPatternOptionValue 拥有这种魔力,它可能会一路走下去,并有一个语言结构来做正确命名参数,您可以通过它们的名称来引用它们.就像其他带有命名参数的语言一样.(同时,我很好奇有哪些可能的解决方法......)

Philosophical Addendum: It seems like if Mathematica is going to have this magic with OptionsPattern and OptionValue it might as well go all the way and have a language construct for doing named arguments properly where you can just refer to them by, you know, their names. Like every other language with named arguments does. (And in the meantime, I'm curious what workarounds are possible...)

推荐答案

这是我的答案的最终版本,包含来自 Brett Champion 的答案的贡献.

Here is the final version of my answer, containing the contributions from the answer by Brett Champion.

ClearAll[def];
SetAttributes[def, HoldAll];
def[lhs : f_[args___] :> rhs_] /; !FreeQ[Unevaluated[lhs], OptionsPattern] :=
   With[{optionNames = Options[f][[All, 1]]},
     lhs := Block[optionNames, optionNames = OptionValue[optionNames]; rhs]];
def[lhs : f_[args___] :> rhs_] := lhs := rhs;

定义在论证中作为延迟规则给出的原因是这样我们可以受益于语法高亮.使用块技巧是因为它适合这个问题:它不会干扰函数内部可能的嵌套词法范围构造,因此不存在意外捕获变量的危险.我们检查 OptionsPattern 是否存在,因为如果没有它,此代码对于定义将不正确,并且我们希望 def 在这种情况下也能工作.使用示例:

The reason why the definition is given as a delayed rule in the argument is that this way we can benefit from the syntax highlighting. Block trick is used because it fits the problem: it does not interfere with possible nested lexical scoping constructs inside your function, and therefore there is no danger of inadvertent variable capture. We check for presence of OptionsPattern since this code wil not be correct for definitions without it, and we want def to also work in that case. Example of use:

Clear[f, a, b, c, d];
Options[f] = {a -> c, b -> d};
(*The default values.*)
def[f[n_, OptionsPattern[]] :> (a + b)^n]

您现在可以查看定义:

Global`f
f[n$_,OptionsPattern[]]:=Block[{a,b},{a,b}=OptionValue[{a,b}];(a+b)^n$]

f[n_,m_]:=m+n

Options[f]={a->c,b->d}

我们现在可以测试了:

In[10]:= f[2]
Out[10]= (c+d)^2

In[11]:= f[2,a->e,b->q]
Out[11]= (e+q)^2

修改是在编译时"完成的,并且非常透明.虽然这个解决方案可以节省一些打字 w.r.t.布雷特的,它在编译时"确定选项名称集,而布雷特的 - 在运行时".因此,它比 Brett 的更脆弱一些:如果在使用 def 定义函数后向函数添加一些新选项,则必须清除它并重新运行 def.然而,在实践中,习惯上从 ClearAll 开始并将所有定义放在一个(单元格)中,因此这似乎不是一个真正的问题.此外,它不能与字符串选项名称一起使用,但您的原始概念也假定它们是符号.此外,它们不应该具有全局值,至少在 def 执行时不应该具有.

The modifications are done at "compile - time" and are pretty transparent. While this solution saves some typing w.r.t. Brett's, it determines the set of option names at "compile-time", while Brett's - at "run-time". Therefore, it is a bit more fragile than Brett's: if you add some new option to the function after it has been defined with def, you must Clear it and rerun def. In practice, however, it is customary to start with ClearAll and put all definitions in one piece (cell), so this does not seem to be a real problem. Also, it can not work with string option names, but your original concept also assumes they are Symbols. Also, they should not have global values, at least not at the time when def executes.

这篇关于可选的命名参数,无需将它们全部包装在“OptionValue"中;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆