2012-09-15 69 views
2

我將OCaml Format模塊轉換爲F#並將問題追溯到使用ocaml Pervasives at_exit。將OCaml轉換爲F#:F#等價於Pervasives at_exit

val at_exit : (unit -> unit) -> unit 

註冊給定函數在程序終止時被調用。註冊at_exit的函數將在程序執行退出或正常終止時調用,或者由於未捕獲的異常而終止。這些函數以「後進先出」順序調用:最近添加的函數at_exit被首先調用。

在轉換過程中,由於編譯器沒有將其標記爲需要,我沒有在代碼中預期到事件,所以我將其註釋掉。

我使用VS Object Browser檢查了FSharp.PowerPack.Compatibility.PervasivesModuleat_exit,發現沒有。

我發現how to run code "at_exit"?How do I write an exit handler for an F# application?

OCaml的線是

at_exit print_flush 

與print_flush簽名:在OCaml的代碼的調試會話期間看使用它val print_flush : (unit -> unit)

而且,看起來像at_exit在初始化結束時和每次使用對模塊的調用結束時被調用。

任何建議,提示如何做到這一點。這將是我在F#中的第一個活動。

編輯

下面是一些什麼,我已經瞭解了格式模塊應該闡明這個問題的一些情況。

Format模塊是一個函數庫,用於提供簡單OCaml值(如int,bool,string)的基本漂亮打印機命令。格式化模塊有像print_string這樣的命令,但也有一些命令說下一行放在一個有界的框中,認爲新的一組左右邊界。所以一個可以寫:

print_string "Hello" 

open_box 0; print_string "<<"; 
open_box 0; print_string "p \/ q ==> r"; close_box(); 
print_string ">>"; close_box() 

open_boxprint_string的命令由一個循環,解釋命令來處理,然後決定枯萎打印在當前行或進到下下一行。這些命令保存在一個隊列中,並且有一個狀態記錄用於保存可變值,例如左邊距和右邊距。

需要啓動隊列和狀態,從調試測試用例反對工作OCaml代碼看起來是在模塊初始化結束時完成的,但在Format模塊中的任何函數進行第一次調用之前完成。通過使用at_exit的機制,隊列和狀態被清理並重新啓動以用於下一組命令,該機制識別用於格式模塊的初始呼叫的最後匹配幀已被移除,從而觸發對at_exit的呼叫,該呼叫推出隊列中剩餘的任何命令並重新初始化隊列和狀態。

因此,調用print_flush的順序至關重要,並且看起來好於OCaml文檔所述。

+1

你可以只把'finally'你的主要方法內部 –

+0

另一個想法 - 持有單一個類型的實例,然後讓程序退出時調用析構函數 –

回答

1

這應做到:

module Pervasives = 
    open System 
    open System.Threading 

    // 
    let mutable private exitFunctions : (unit -> unit) list = List.empty 

    // 
    let mutable private exitFunctionsExecutedFlag = 0 

    // 
    let private tryExecuteExitFunctions _ = 
     if Interlocked.CompareExchange (&exitFunctionsExecutedFlag, 1, 0) = 0 then 
      // Run the exit functions in last-in-first-out order. 
      exitFunctions 
      |> List.iter (fun f -> f()) 

    // Register handlers for events which fire when the process exits cleanly 
    // or due to an exception being thrown. 
    do 
     AppDomain.CurrentDomain.ProcessExit.Add tryExecuteExitFunctions 
     AppDomain.CurrentDomain.UnhandledException.Add tryExecuteExitFunctions 

    // 
    let at_exit f = 
     // TODO : This function should be re-written using atomic operations 
     // for thread-safety! 
     exitFunctions <- f :: exitFunctions 

和一些代碼來測試它:

open System 

// Register a couple of handlers to test our code. 
Pervasives.at_exit <| fun() -> 
    Console.WriteLine "The first registered function has fired!" 

Pervasives.at_exit <| fun() -> 
    Console.WriteLine "The second registered function has fired!" 
    TimeSpan.FromSeconds 1.0 
    |> System.Threading.Thread.Sleep 
    Console.WriteLine "Exiting the second registered function!" 

Pervasives.at_exit <| fun() -> 
    Console.WriteLine "The third registered function has fired!" 

// Do some stuff in our program 
printfn "blah" 
printfn "foo" 
printfn "bar" 

(* The functions we registered with at_exit should be fired here. *) 

// Uncomment this to see that our handlers work even when the 
// program crashes due to an unhandled exception. 
//failwith "Uh oh!" 
+0

我還沒有測試過這個答案,但是一旦我做了,就會發布結果。 :) –