2011-01-05 71 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已經是尾遞歸了。