2

私は OCaml Formatモジュールを F# に変換しており、問題を追跡して OCaml Pervasives at_exit の使用に遡ります。

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

プログラムの終了時に呼び出される関数を登録します。で登録された関数at_exitは、プログラムが exit を実行したとき、または通常どおりまたはキャッチされていない例外のために終了したときに呼び出されます。関数は「後入れ先出し」の順序で呼び出されます。最後に追加された関数at_exitが最初に呼び出されます。

変換の過程で、コンパイラが必要としてフラグを立てず、コード内のイベントを予期していなかったため、行をコメントアウトしました。

VS Object Browser の使用を確認しましたが、何も見つかりませんでしFSharp.PowerPack.Compatibility.PervasivesModuleた。at_exit

コード「at_exit」を実行する方法を見つけましたか? F# アプリケーションの終了ハンドラーを作成するにはどうすればよいですか?

OCamlラインは

at_exit print_flush 

print_flush 署名付き: val print_flush : (unit -> unit)

また、OCaml コードのデバッグ セッション中の使用を見るとat_exit、初期化の最後とモジュールへの呼び出しの各使用の最後に呼び出されているように見えます。

これを行う方法に関する提案、ヒント。これは、F# での最初のイベントになります。

編集

問題を明らかにする Format モジュールについて私が学んだことの一部を次に示します。

Format モジュールは、int、bool、string などの単純な OCaml 値の基本的なきれいなプリンター コマンドの関数のライブラリです。format モジュールには のようなコマンド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_boxやなどのコマンドprint_stringは、コマンドを解釈し、現在の行に出力するか、次の行に進むかを決定するループによって処理されます。コマンドはキューに保持され、左右のマージンなどの変更可能な値を保持する状態レコードがあります。

キューと状態を準備する必要があります。これは、動作中の OCaml コードに対してテスト ケースをデバッグすることから、モジュールの初期化の最後に行われるように見えますが、Format モジュール内の関数への最初の呼び出しが行われる前に行われます。at_exitキューと状態はクリーンアップされ、フォーマット モジュールへの最初の呼び出しで最後に一致したフレームが削除されたことを認識するメカニズムを使用して、次のコマンド セットのために再度準備され、残りのフレームat_exitを押し出す呼び出しがトリガーされます。コマンドをキューに入れ、キューと状態を再初期化します。

したがって、 への呼び出しの順序付けprint_flushは重要であり、OCaml のドキュメントに記載されている以上のもののようです。

4

1 に答える 1

2

これはそれを行う必要があります:

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!"
于 2012-09-28T16:32:14.453 に答える