2011-01-05 41 views
1

我想问如果异常:“异常STACK_OVERFLOW”可能导致无限循环,特别是异常下面的代码出现:异常“STACK_OVERFLOW” OCaml中

(*the loop "while" should stop when both stacks are empty*) 
    while (not (Stack.is_empty stackFalse))|| (not (Stack.is_empty stackTrue)) do  
    (
     if (not (Stack.is_empty stackTrue)) then 
     (
      let q1 = Stack.pop stackTrue in 
      let (_,_,ptrs) = fst (Hashtbl.find graph (fst q1)) in 
      List.iter (fun elem -> 

          let app = Hashtbl.find graph elem in 
          let (typeNode,last,ptrs') = fst app in 

          if typeNode = "Or-node" then 
          (
           Stack.push (elem,true) stackTrue; 
           Hashtbl.add labeled elem true 
          ) 
          else if last = false then               
           Hashtbl.replace graph elem ((typeNode,true,ptrs'),snd app) 
          else 
          (
           Stack.push (elem,true) stackTrue; 
           Hashtbl.add labeled elem true 
          )  ) ptrs ; 
     ); 

     if (not (Stack.is_empty stackFalse)) then    
     (
      let q2 = Stack.pop stackFalse in 
      let (_,_,ptrs1) = fst (Hashtbl.find graph (fst q2))in 

      List.iter (fun elem -> 

          let app = Hashtbl.find graph elem in 
          let (typeNode,last,ptrs') = fst app in 

          if typeNode = "And-node" then 
          (
           Stack.push (elem,false) stackFalse; 
           Hashtbl.add labeled elem false 
          )        
          else if last = false then               
           Hashtbl.replace graph elem ((typeNode,true,ptrs'),snd app) 
          else 
          (
           Stack.push (elem,false) stackFalse; 
           Hashtbl.add labeled elem false 
          ) ) ptrs1 ; 
     ); 

    ) 
    done; 
+2

为了更加习惯于函数式编程,你应该用一个列表替换你的'Stack',并用递归调用替换'while'循环。是否有理由将本节编程为强制性风格? – nlucaroni 2011-01-05 15:04:20

+2

通常不会,while循环不会导致堆栈溢出 - 没有堆栈。 – 2011-01-05 16:40:31

回答

8

标准急救:使用-g重新编译并使用OCAMLRUNPARAM = b运行(参见手册)以查看回溯。

PS我会怀疑结构比较(例如Hashtbl.find使用),在hashtbl元素中是否有任何循环引用?

6

当您进入调用者函数时,堆栈会增长。 while循环和尾调用不会增加堆栈,所以Stack_overflow错误不会导致诸如循环之类的结果。

正如ygrek所建议的那样,如果您使用结构比较运算符=,循环数据结构可能会引发堆栈溢出。您在代码中使用=Hashtbl模块在内部使用Pervasives.compare;如果hashtbl键是循环的,则所有使用键的操作可能会运行到无限循环。在这种情况下,一个很好的解决方法是使用HasthblHashtbl.Make)的模块化形式,它允许您提供定制的,循环感知的相等函数。

堆栈溢出的一个更常见的原因是标准库的List模块的某些功能不是尾递归的。如果使用足够小的堆栈限制足够大的列表,它们可能会导致堆栈溢出。在这种情况下,使用Extlib或Batteries的List模块(提供tailrec实现)是一个很好的解决方案。然而这不是你的问题,因为List.iter已经是尾递归了。