Events 将OCaml转换为F#:F#在#出口处的渗透物的模糊性

Events 将OCaml转换为F#:F#在#出口处的渗透物的模糊性,events,f#,ocaml,Events,F#,Ocaml,我正在将OCaml模块转换为F#,并将问题追溯到在#出口使用OCaml val at_exit : (unit -> unit) -> unit 注册要在程序终止时调用的给定函数。当程序执行exit或终止时(正常或由于未捕获的异常),将调用在退出时注册的函数。函数按“后进先出”的顺序调用:最新添加的函数在_exit处首先调用 在转换过程中,我注释掉了该行,因为编译器没有将其标记为需要,并且我不希望代码中出现事件 我使用VS Object Browser在退出时检查了的FSharp.

我正在将OCaml模块转换为F#,并将问题追溯到在#出口使用OCaml

val at_exit : (unit -> unit) -> unit
注册要在程序终止时调用的给定函数。当程序执行exit或终止时(正常或由于未捕获的异常),将调用在退出时注册的函数。函数按“后进先出”的顺序调用:最新添加的函数在_exit处首先调用

在转换过程中,我注释掉了该行,因为编译器没有将其标记为需要,并且我不希望代码中出现事件

我使用VS Object Browser在退出时检查了
FSharp.PowerPack.Compatibility.pervasiveModule
,但没有发现任何问题

我确实找到了

OCaml线是

at_exit print_flush 
带打印刷新签名:
val打印刷新:(单位->单位)

此外,在OCaml代码的调试会话期间查看它的使用情况时,它看起来像是在初始化结束时和每次使用模块调用结束时都调用了退出时的

任何关于如何做到这一点的建议和提示。这将是我在F#的第一次活动

编辑

下面是我所学到的一些关于格式模块的知识,这些知识应该会对这个问题有所帮助

Format模块是一个函数库,用于简单OCaml值(如int、bool、string)的基本漂亮打印机命令。格式模块有类似于
print\u string
的命令,但也有一些命令可以说,将下一行放入一个有边界的框中,考虑一组新的左右边距。所以我们可以写:

print_string "Hello"

打开_框0;打印字符串“>”;关闭_框()
诸如
open_box
print_string
之类的命令由一个循环处理,该循环解释这些命令,然后决定在当前行上打印或前进到下一行。这些命令保存在队列中,并且有一个状态记录来保存可变值,例如左边距和右边距

队列和状态需要初始化,根据工作的OCaml代码调试测试用例似乎是在模块初始化结束时,但在对Format模块中的任何函数进行第一次调用之前完成的。队列和状态被清理,并通过使用
at_exit
机制再次启动,以执行下一组命令,该机制识别出对格式模块的初始调用的最后一个匹配帧已被删除,从而触发对
at_exit
的调用,从而推出队列中的任何剩余命令,并重新初始化队列和状态

因此,调用
print\u flush
的顺序非常关键,似乎比OCaml文档中所述的顺序更重要。

这应该可以做到:

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
模块渗透=
开放系统
开放系统。线程
//
让可变私有exitFunctions:(单位->单位)list=list.empty
//
让可变私有exitFunctionsExecutedFlag=0
//
让私有tryexecuteexit函数=
如果Interlocated.CompareExchange(&exitFunctionsExecutedFlag,1,0)=0,则
//按后进先出的顺序运行退出功能。
退出函数
|>List.iter(funf->f())
//为进程完全退出时触发的事件注册处理程序
//或者由于引发了异常。
做
AppDomain.CurrentDomain.ProcessExit.Add TryExecuteExit函数
AppDomain.CurrentDomain.UnhandledException.Add TryExecuteExit函数
//
让我们在f出口下车=
//TODO:应该使用原子操作重新编写此函数
//为了线程安全!
exitFunctions System.Threading.Thread.Sleep
Console.WriteLine“退出第二个注册函数!”
出口处的渗透物
Console.WriteLine“第三个注册函数已启动!”
//在我们的节目中做一些事情
打印fn“废话”
打印fn“foo”
打印fn“条”
(*我们在_exit注册的函数应在此处启动。*)
//取消对此的注释,以查看我们的处理程序即使在
//由于未处理的异常,程序崩溃。
//用“啊哦!”

你可以在你的主方法中放入一个
最后一个
,另一个想法-保留一个类型的实例,然后让析构函数在程序退出时被调用。我还没有测试这个答案,但一旦我测试了,就会发布结果。:)
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!"