Recursion 在Mathematica中,为什么递归函数中的替换不';不要终止?
假设我在Mathematica中定义了一个递归阶乘,如下所示:Recursion 在Mathematica中,为什么递归函数中的替换不';不要终止?,recursion,replace,wolfram-mathematica,Recursion,Replace,Wolfram Mathematica,假设我在Mathematica中定义了一个递归阶乘,如下所示: Clear[fact] fact[0] = 1 fact[n_] := n fact[n - 1] 评估事实[10]确认函数工作并终止 这是一个很重要的例子,但在这个问题上,它起到了作用。实际上,我的问题与递归函数定义有关 我希望评估以下替换也将终止: x fact[x-1] /. x -> 2 唉,它运行在递归深度限制中: $RecursionLimit::reclim: Recursion depth of 256 e
Clear[fact]
fact[0] = 1
fact[n_] := n fact[n - 1]
评估事实[10]确认函数工作并终止
这是一个很重要的例子,但在这个问题上,它起到了作用。实际上,我的问题与递归函数定义有关
我希望评估以下替换也将终止:
x fact[x-1] /. x -> 2
唉,它运行在递归深度限制中:
$RecursionLimit::reclim: Recursion depth of 256 exceeded.
我希望看到这样的情况:
2 fact[2-1]
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)
或者只是价值
2
更新:事实的另一种递归定义按预期工作:
Clear[fact]
fact[n_] := If[n < 1, 1, n fact[n - 1]]
Clear[事实]
事实[n_]:=如果[n<1,1,n事实[n-1]]
但这个事实(双关语;-)让我更加神秘:为什么它的行为如此不同
我的问题有两个:
/Twan尝试
u[x]:=x;跟踪[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]
在保留第一个参数时给出所需的2
,并按预期替换,然后释放保留
另一种方法是
Unprotect[ReplaceAll]
SetAttributes[ReplaceAll, HoldFirst]
ReplaceAll[x*fact[x - 1], x -> 2]
但不要这样做
当然,很快会有人给出更好的解释
编辑:回答关于为什么的新增问题
Clear[factif]
factif[n_] := If[n < 1, 1, n factif[n - 1]]
Clear[factif]
如果[n<1,1,n如果[n-1]]
不会导致无限递归:这样定义,
factif[x]
的计算结果为If[x<1,1,x factif[x-1]]
,因为x这是因为您在计算:
fact[x-1]
在更换之前。只要做fact[x-1]
你就会得到错误
您可以这样修复事实函数:
Clear[fact]
fact[0] = 1
fact[n_Integer?Positive] := n fact[n - 1]
然后x事实[x-1]/。x->2
返回似乎正确的2
请记住,函数参数模式fact[n.]
非常通用。例如,它允许像fact[Integrate[Sin[x],x]]
这样的东西进行计算,这可能不是您想要的。使用fact[n_Integer]
更精确,并允许fact
函数按您希望的方式运行
如果您想更好地定义此函数,可以执行以下操作:
2 fact[2-1]
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)
因此,类似于fact[“x”]
的操作将失败,并显示一条消息:
fact::nicetrybuddy: fact[x] is not defined.
其他答案是正确的:fact
在替换其参数之前进行计算。关键问题是,您已经定义了fact
,并考虑了整数输入,而没有为非整数输入提供终端条件。如果你真的这么做了
Clear[fact]
fact[0] = 1
fact[n_Integer?Positive] := n fact[n - 1]
然后,fact
将保持未计算状态,直到它具有匹配正整数的内容
您可能需要将替换语句包装在Evaluate
中,然后在替换其参数后触发事实的定义
另一种方法可能是使用纯函数:
# fact[#-1]& @ 2
这不应该过早地进行评估。我现在正在运行一个大型模拟(400000个Hodrick-Prescott过滤器!),所以我没有用纯函数检查最后一个建议。我考虑过这一点。但我已经尝试过不同的递归函数,例如列表。我也遇到了同样的行为。所以我尽可能地把这个问题贴出来。但一个例子确实使事情再次具体化。抱歉。啊哈,这是有道理的:Mathematica首先计算/的LHS。然后执行替换。使用Hold[]可以推迟“急切”的评估。谢谢你的回答:有效、相关、清晰、简洁!我的compliments@nanitous干杯如果三个答案中有一个确实回答了您的问题,您可以将其标记为已接受的答案,这样它就会出现在顶部(这会提高回答者的声誉)。添加一个全面条款是个好主意!我得记住那个。