为什么默认行为会这样?

14

我们可以为函数的参数设置默认值

Default[f] = 5;

接着使用:

f[a_, b_.] := {a, b}

f[1, 2]
f[1]
   {1, 2}
   {1, 5}

这将创建以下数值:

DefaultValues[f]
DownValues[f]
   {HoldPattern[Default[f]] :> 5}
   {HoldPattern[f[a_, b_.]] :> {a, b}}

从这个定义可以看出,值5并不是固定在函数f的定义中,而是用于DefaultValues赋值。但是,如果我们通过直接更改或使用以下方式更改DefaultValues

Default[f] = 9;

DefaultValues[f]
{HoldPattern[Default[f]] :> 9}

然后再次使用 f:

f[1]
{1, 5}

可以看到新值被使用。

因此,我的问题是:

  • f[a_, b_.] := {a, b}使用的默认值为什么不会随着DefaultValues而改变?

  • 真正的默认值(5)存储在哪里,因为它既不出现在DownValues中也不出现在DefaultValues中?


+1 很好,清晰明了。希望答案也是如此! - Simon
你为什么不定义默认值为 f[a_,b_:5]:=... 呢? - user616736
@yoda:因为这个想法是为了在需要时能够更改默认设置。 - Simon
@yoda 如果“Default”值很长和/或经常使用,则编写“_”更加简洁。 - Mr.Wizard
我认为这个问题有价值,这就是为什么我在4个月前已经点赞了它。我的问题从来不是关于这个问题的,因为我同样好奇它们在哪里以及如何定义。我只是想指出对我来说它似乎不像一个错误。然而,我意识到自从上一次有意义的讨论已经过去了4个月,我已经忘记了具体是什么,并从我的答案下的评论中刷新了我的记忆,我同意你的观点。事实上,我甚至在4个月前的评论中提到它看起来像一个错误。所以,我道歉并撤回评论 :) - user616736
显示剩余2条评论
3个回答

10

不是答案,但是:
利用默认值保留到函数被重新定义的行为建议快速解决问题:

在任何其他定义之前定义一个全局变量 Default

In[1]:= Default[f]:=$f
In[2]:= f[a_.]:=a

In[3]:= f[]
Out[3]= $f

In[4]:= $f=5; f[]
Out[5]= 5
In[6]:= $f=6; f[]
Out[7]= 6
In[8]:= $f=.; f[]
Out[9]= $f

这也适用于 Optional

In[1]:= g[a_:$g] := a

In[2]:= g[]
Out[2]= $g

In[3]:= $g=1; g[]
Out[4]= 1

8
文档中可以得知,Default[f]所需的值必须在使用_.作为f的参数之前定义好。在设置Default[f] = 9;后重新定义f将使用新的默认值。因此,我猜测它在第一次定义f时被内部定义,并且即使DefaultValue@f存储了新值,它也不会改变。

3
它的内部存储位置在哪里?旧的默认值似乎没有出现在任何 *Values 中... - Simon
2
@Mr.W:非常抱歉,但这只是一个可能的解释,而不是具体的答案(以防您在文档中错过了这一部分)。此外,由于这是记录下来的行为,我不明白第一个问题的意义(它就是它)。但是第二个问题,我确实不知道,也没有尝试回答。我想我应该表明我的意图。 - user616736
2
抱歉如果我说话有些粗鲁。我知道除了管理员之外,其他人看不到我的投票,但是不知怎么的,我觉得需要解释一下为什么我不投票支持这个提议,但我担心我的表达听起来有贬低的意味。至于“默认值”,对我来说,你回答中的引用并不排除“Default[f]”后来可能会被更改,并且该更改将影响先前的使用。(检查“DownValues”表明这应该可以工作。)相反,它告诉我,在没有定义“Default”的情况下使用“_.”可能会在赋值期间注册为错误。 - Mr.Wizard
3
问题似乎出在全局规则上。您可以尝试在本地使用f的示例:f[1] /. f[a_, b_.] :> {a, b}(首先删除其全局定义),并看到它对Default[f]的更改是敏感的。 我猜测全局规则(定义)可能在定义时会经历一些内部优化,这需要在定义时考虑Default的值。 定义完成后,它将被优化并且不会对Default[f]的更改敏感,除非我们有一个间接层次,就像@Simon的答案中所述。 - Leonid Shifrin
2
@Alexey 对我来说还不清楚这是在一般求值时发生的,还是只与SetSetDelayed以及赋值过程有关。因为我怀疑后者(否则就不清楚在f[1] /. f[a_, b_.] :> {a, b}中局部规则中可选模式的求值为什么不会导致相同的“默认”-不敏感行为),而且由于SetSetDelayed产生全局规则,我称其为“全局规则效应”。 - Leonid Shifrin
显示剩余17条评论

3
我发现这种行为在本地规则的情况下是由于RuleDelayed内部特定细节所致。
比较:
In[1]:= Default[f] = 5;
replaceAll[f[1], 
  f[a_, b_.] :> Unevaluated@{a, b}] /. (Default[f] = 9; replaceAll) ->
   ReplaceAll

Default[f] = 5;
Block[{RuleDelayed}, 
 replaceAll[f[1], 
   f[a_, b_.] :> Unevaluated@{a, b}] /. (Default[f] = 9; 
    replaceAll) -> ReplaceAll]

Out[2]= {1, 5}

Out[4]= Unevaluated[{1, 9}]

可以看到,Blocking RuleDelayed 会使得本地的规则表现得符合预期。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接