nan*_*ous 7 recursion replace wolfram-mathematica
想象一下,我在Mathematica中定义了一个递归因子,如下所示:
Clear[fact]
fact[0] = 1
fact[n_] := n fact[n - 1]
Run Code Online (Sandbox Code Playgroud)
评估事实[10]证实该功能有效并终止.
这是一个主要的例子,但它在这个问题中起到了作用.实际上,无论如何,我的问题一般都与递归函数定义有关.
我期望评估以下替换以终止:
x fact[x-1] /. x -> 2
Run Code Online (Sandbox Code Playgroud)
唉,它运行到递归深度限制:
$RecursionLimit::reclim: Recursion depth of 256 exceeded.
Run Code Online (Sandbox Code Playgroud)
我希望看到类似的东西:
2 fact[2-1]
Run Code Online (Sandbox Code Playgroud)
或只是价值
2
Run Code Online (Sandbox Code Playgroud)
更新:事实 的另一种递归定义确实按预期工作:
Clear[fact]
fact[n_] := If[n < 1, 1, n fact[n - 1]]
Run Code Online (Sandbox Code Playgroud)
但是这个事实(双关语意图;-)让我更加神秘:它为什么表现得如此不同?
我的问题是双重的:
即使有内置的帮助和搜索网络的线索,我也无法解释为什么Mathematica坚持,显然,保持符号结果,而不是评估"中间"结果并很好地终止.谁冒险进行了可行的解释?
我如何说服Mathematica根据我的预期执行(除了使用If [] 之外的替代方案)?
我真的对这个感到困惑,我真的希望有人可以帮助我.
/ M炼
尝试u[x_] := x; Trace[x*u[x] /. x -> 2],它首先评估x和u[x].在您的情况下,它首先尝试fact[x-1]在替换x为2 之前进行求值,并达到递归限制.
Attributes[ReplaceAll]表明它没有属性HoldFirst,所以它首先评估它的第一个参数.例如,
ReleaseHold@ReplaceAll[Hold[x*fact[x - 1]], x -> 2]
Run Code Online (Sandbox Code Playgroud)
给出预期的2,因为它拥有第一个参数,替换,然后按预期释放保持.
另一种方法是
Unprotect[ReplaceAll]
SetAttributes[ReplaceAll, HoldFirst]
ReplaceAll[x*fact[x - 1], x -> 2]
Run Code Online (Sandbox Code Playgroud)
但不要这样做.
当然有人会尽快给出更好的解释.
编辑:回答关于原因的补充问题
Clear[factif]
factif[n_] := If[n < 1, 1, n factif[n - 1]]
Run Code Online (Sandbox Code Playgroud)
不会导致无限递归:以这种方式定义,factif[x]求值为If[x < 1, 1, x factif[x - 1]],因为x<1无法求值.因此,在尝试评估第一个参数后ReplaceAll,它仍然保持这种形式,然后更换发生等.
这是因为你正在评估这个:
fact[x-1]
Run Code Online (Sandbox Code Playgroud)
在更换之前.只是做fact[x-1],你得到错误.
您可以fact像这样修复您的功能:
Clear[fact]
fact[0] = 1
fact[n_Integer?Positive] := n fact[n - 1]
Run Code Online (Sandbox Code Playgroud)
然后x fact[x - 1] /. x -> 2返回2看似正确的.
记住,你的函数参数模式fact[n_]是非常一般.例如,它允许fact[Integrate[Sin[x], x]]评估的内容,这可能不是您想要的.使用fact[n_Integer]更加精确,并且允许fact函数按照您希望的方式运行.
如果您想更好地定义此功能,您可以执行以下操作:
Clear[fact]
fact::nicetrybuddy = "fact[``] is not defined.";
fact[0] = 1
fact[n_Integer?Positive] := n fact[n - 1]
fact[n_] := (Message[fact::nicetrybuddy, n]; $Failed)
Run Code Online (Sandbox Code Playgroud)
所以类似的东西fact["x"]会失败并带有消息:
fact::nicetrybuddy: fact[x] is not defined.
Run Code Online (Sandbox Code Playgroud)