在 Mathematica 中,为什么递归函数中的替换不会终止?
想象一下,我在 Mathematica 中定义了一个递归阶乘,如下所示:
Clear[fact]
fact[0] = 1
fact[n_] := n fact[n - 1]
评估fact[10] 确认该函数有效并终止。
这是一个主要的例子,但它在这个问题中达到了它的目的。实际上,我的问题总体上与递归函数定义有关。
我预计评估以下替换也将终止:
x fact[x-1] /. x -> 2
唉,它遇到了递归深度限制:
$RecursionLimit::reclim: Recursion depth of 256 exceeded.
我预计会看到类似的内容:
2 fact[2-1]
或只是值
2
UPDATE:fact 的替代递归定义 确实按预期工作:
Clear[fact]
fact[n_] := If[n < 1, 1, n fact[n - 1]]
但是这个事实(双关语;-)让我更加神秘:为什么它的行为如此不同?
我的问题是双重的:
即使有内置的帮助并在网上搜索线索,我也无法解释为什么 Mathematica 显然坚持保留符号结果,而不是评估“中间”结果并很好地终止。谁敢提出可行的解释?
我如何说服 Mathematica 按照我的期望执行(除了使用 If[] 的替代方案)?
我真的很困惑这个问题,我真的希望有人能帮助我。
/吐温
Imagine I've defined a recursive factorial in Mathematica, like this:
Clear[fact]
fact[0] = 1
fact[n_] := n fact[n - 1]
Evaluating fact[10] confirms that the function works and terminates.
A bit of a staple example, but it serves its purpose in this question. Actually, my question pertains to recursive function definitions in general anyway.
I expected evaluating the following replacement to terminate as well:
x fact[x-1] /. x -> 2
Alas, it runs in to a recursion depth limit:
$RecursionLimit::reclim: Recursion depth of 256 exceeded.
I expected to see something like:
2 fact[2-1]
or just the value
2
UPDATE: An alternative recursive definition of fact does work as expected:
Clear[fact]
fact[n_] := If[n < 1, 1, n fact[n - 1]]
But this fact (pun intended ;-) makes it even more mysterious to me: Why does it behave so much differently?
My question is twofold:
Even with the built-in help and searching the net for clues, I can't explain why Mathematica insists in, apparently, keeping the symbolic result, rather than evaluating the 'intermediate' results and terminating nicely. Who ventures a viable explaination?
How can I convince Mathematica to perform according to my expections (Other than using the alternative using If[])?
I'm really puzzled by this one, and I really hope someone out there can help me out.
/Twan
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
尝试 u[x_] := x;跟踪[x*u[x] /。 x-> 2],它首先评估
x
和u[x]
。那么,在您的情况下,它首先尝试评估fact[x-1]
,然后将x
替换为 2,并达到递归限制。Attributes[ReplaceAll]
显示它没有属性HoldFirst
,因此它首先评估其第一个参数。例如,给出预期的
2
,因为它保存第一个参数,替换,然后释放保留,如您所愿。另一种方法是
但不要这样做。
不过,肯定很快就会有人给出更好的解释。
编辑:为了回答关于为什么
不会导致无限递归的附加问题:以这种方式定义,
factif[x]
计算结果为If[x
1, 1, x factif[x - 1]]
,因为无法计算x<1
。因此,在尝试评估ReplaceAll
的第一个参数之后,它仍保持这种形式,然后发生替换等。Trying
u[x_] := x; Trace[x*u[x] /. x -> 2]
, it first evaluatesx
andu[x]
. In your case, then, it first tries to evaluatefact[x-1]
before replacingx
by 2, and hits the recursion limit.Attributes[ReplaceAll]
shows that it does not have attributeHoldFirst
, so it starts by evaluating its first argument. For instance,gives the expected
2
, as it holds the first argument, replaces, then releases the hold, as you intended.Another way to do it is
but don't do this.
Surely someone will give a better explanation soon, though.
EDIT: In response to the added question as to why
does not result in infinite recursion: defined this way,
factif[x]
evaluates toIf[x < 1, 1, x factif[x - 1]]
, sincex<1
cannot be evaluated. So it remains in this form after the attempted evaluation of the first argument ofReplaceAll
, then the replacement occurs etc.这是因为您正在评估这一点:
在更换发生之前。只需执行
fact[x-1]
即可得到错误。您可以像这样修复您的
fact
函数:然后
x fact[x - 1] /。 x-> 2
返回2
这似乎是正确的。请记住,您的函数参数模式
fact[n_]
是极其通用的。例如,它允许对诸如fact[Integrate[Sin[x], x]]
之类的内容进行评估,这可能不是您想要的。使用fact[n_Integer] 更加精确,并且允许fact 函数按照您想要的方式运行。如果您想更好地定义此函数,您可以执行以下操作:
这样
fact["x"]
之类的操作将失败并显示一条消息:This is because you're evaluating this:
before the replacement happens. Just do
fact[x-1]
and you get the error.You can fix your
fact
function like so:Then
x fact[x - 1] /. x -> 2
returns2
which seems correct.Remember that your function argument pattern
fact[n_]
is extremely general. For example it allows for something likefact[Integrate[Sin[x], x]]
to evaluate, which is probably not something you intended. Usingfact[n_Integer]
is much more precise, and will allow thefact
function to act the way you want it to.If you want to define this function even better, you can do something like:
So that something like
fact["x"]
will fail with a message:其他答案是正确的:
fact
在其参数被替换之前评估。根本问题是您已经定义了事实并考虑了整数输入,并且没有为非整数输入提供终止条件。如果您这样做,则
fact
将保持未计算状态,直到它具有与正整数匹配的内容为止。您可能需要将替换语句包装在
Evaluate
中,然后在替换其参数后触发fact
的定义。另一种方法可能是使用纯函数:
不应该过早地求值。
The other answers are correct:
fact
evaluates before its argument is replaced. The essential issue is that you have definedfact
with integer inputs in mind, and haven't provided a terminal condition for non-integer inputs. If you instead didThen
fact
would be left unevaluated until it had something that matched a positive integer.You might need to wrap your replacement statement in
Evaluate
to then fire the definition forfact
after replacing its argument.An alternative approach might be to use a pure function:
That shouldn't evaluate prematurely.