Recursion OCaml中求值期间的堆栈溢出

Recursion OCaml中求值期间的堆栈溢出,recursion,ocaml,stack-overflow,Recursion,Ocaml,Stack Overflow,我在Alexandria的Heron实现平方根近似算法时遇到堆栈溢出问题,如下所示: let squareRoot (x : float) : float = let rec aux input guess = if abs_float(guess**2. -. input) < 0.0001 then guess else aux input (guess +. input/.guess)/.2. in aux x 1.;; def squareRoot(x):

我在Alexandria的Heron实现平方根近似算法时遇到堆栈溢出问题,如下所示:

let squareRoot (x : float) : float =
  let rec aux input guess =
    if abs_float(guess**2. -. input) < 0.0001 then guess
    else aux input (guess +. input/.guess)/.2. in
  aux x 1.;;
def squareRoot(x):
  def aux (s, guess):
    if abs(pow(guess,2) - s) < 0.0001:
      return guess
    else:
      return aux (s, (guess + s/guess)/2)
  return aux (x, 1)
我们从一个初始(差)近似答案开始,即平方根为1.0,然后继续改进猜测,直到我们在真实答案的增量范围内。通过使用x/guess对当前猜测进行平均来实现改进。答案精确到delta=0.0001以内

我的实施尝试如下:

let squareRoot (x : float) : float =
  let rec aux input guess =
    if abs_float(guess**2. -. input) < 0.0001 then guess
    else aux input (guess +. input/.guess)/.2. in
  aux x 1.;;
def squareRoot(x):
  def aux (s, guess):
    if abs(pow(guess,2) - s) < 0.0001:
      return guess
    else:
      return aux (s, (guess + s/guess)/2)
  return aux (x, 1)
…运行良好。因此,我使用了OCaml代码,并将我最初的尝试更改为:

let squareRoot (x : float) : float =
  let improve i g = (g +. i/.g)/.2. in
  let rec aux input guess =
    if abs_float(guess ** 2. -. input) < 0.0001 then guess
    else aux input (improve input guess) in
  aux x 1.;;
let平方根(x:float):float=
让我们改进ig=(g+.i/.g)/.2。在里面
让rec aux输入猜测=
如果abs_浮动(猜测**2.-.输入)<0.0001,则猜测
else辅助输入(改进输入猜测)输入
辅助x 1。;;
我所做的更改是将算法的改进部分包装在一个单独的函数中,但现在代码运行成功,没有任何堆栈溢出错误

如果有人能解释为什么会这样,以及OCaml REPL/编译器背后的机制可能无法在我的第一次代码迭代中识别递归调用中的终止条件,我将不胜感激

(应用
aux
发生在被
2除法之前。
…)

被解析为

  (aux input (guess +. input/.guess))/.2

你真的想要吗

  aux input ((guess +. input/.guess)/.2.)
甚至(阅读关于s的文章)

(这可能更容易阅读,有些人使用的名字像
guess'

顺便说一句,有些人会编码

  let guess =  aux input ((guess +. input/.guess)/.2.)
  in aux input guess
(没有递归,但是)

但我不喜欢这样编码(重复使用相同的名称
guess


根据经验,使用括号(或相同的
begin
end
)和中间
let
绑定时不要害羞。两者都使代码更具可读性。

您可以添加一些调试
Printf.eprintf
或使用Ocamldebugger@BasileStarynkevitch谢谢你的建议!我只在OCaml上玩了几天,如果这是一个太琐碎的问题,很抱歉。这是一个简单的语义错误,我想这里有一些更大的背景故事/facepalm非常感谢你!