1

我不明白,为什么这个递归结束:

In[27]:= MyFunc[n_] := MyFunc[n] = 2;
MyFunc[3]

Out[28]= 2

不应该是无止境的吗

MyFunc[3]
MyFunc[3] = 2
(MyFunc[3] = 2) = 2

等等?

为什么会这样

MyFunc[n_] := MyFunc[n];
MyFunc[3]

During evaluation of In[31]:= $IterationLimit::itlim: Iteration limit of 4096 exceeded. >>

Out[33]= Hold[MyFunc[3]]

导致“迭代”限制错误,而不是递归限制?

4

1 回答 1

1

我的另一个回答掩盖了一些重要的细节。这是第二个,我希望更好的一个:

SetDelayed有属性HoldAllSet有属性HoldFirst。所以,你的定义

MyFunc[n_] := MyFunc[n] = 2;

存储时不评估任何部分。仅当您调用它时,例如 MyFunc[3]rhs 才被评估,在这种情况下为涉及Set,的表达式MyFunc[3] = 2。由于Set具有属性HoldFirst,因此该规则与其第一个参数(lhs)一起存储,但未计算。在这个阶段,不重新评估表达式MyFunc[3]的 lhs 。Set但如果是这样,Mathematica 将找到规则MyFunc[3] = 2并计算结果MyFunc[3]2而不使用 lhs 规则MyFunc[n_]

你的第二个定义,

MyFunc[n_] := MyFunc[n];

也存储未评估。但是,当您调用函数时,例如 myFunc[3]rhs 会被评估。rhs 评估为,MyFunc[3]或者,如果你愿意,另一个调用MyFunc. 在MyFunc[3]Mathematica 的评估过程中找到存储的重写规则MyFunc[n_] := MyFunc[n]并应用它。反复。请注意,Mathematica 将此视为迭代而不是递归。

我并不完全清楚评估表达式的 lhs 可能实际上意味着什么。当然,像这样的调用MyFunc[3+4]实际上会导致MyFunc[7]被评估,因为 Mathematica 贪婪地评估函数调用的参数。

事实上,当试图理解这里发生的事情时,可能更容易忘记赋值和左右两边,并记住一切都是表达式,例如,

MyFunc[n_] := MyFunc[n] = 2;

只是一种写作方式

SetDelayed[MyFunc[n_], MyFunc[n] = 2]
于 2013-01-22T15:42:17.017 回答