代码之家  ›  专栏  ›  技术社区  ›  dreeves

Mathematica中的可选命名参数

  •  11
  • dreeves  · 技术社区  · 15 年前

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

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

    以下是的命名参数版本的示例输入和输出 :

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

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

    3 回复  |  直到 13 年前
        1
  •  11
  •   Mr.Wizard naktepe    13 年前

    我在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]
    
        2
  •  6
  •   Janus    14 年前

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

    OptionValue[name] 等于 OptionValue[f,name] 在哪里 f 是转换规则左侧的头,其中 选项值[名称] 出现。

    插入一个显式的 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 仍然存在(尽管没有记录),但是 选择值 这种方法的优点是,您会收到针对不存在选项的警告(例如 foo[d->3] )这也是你第二次回应的情况,但不是你已经接受的回应。

        3
  •  1
  •   dreeves    15 年前

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

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