events - 将 OCaml 转换为 F# : F# equivelent of Pervasives at_exit

标签 events f# ocaml

我正在转换 OCaml Format模块到 F# 并将问题追溯到 OCaml 的使用 Pervasives at_exit。

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

注册要在程序终止时调用的给定函数。当程序正常执行或终止时,将调用 at_exit 注册的函数。未捕获的异常。这些函数按照“后进先出”的顺序调用:首先调用最近使用 at_exit 添加的函数。

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

我使用 VS 对象浏览器检查了 FSharp.PowerPack.Compatibility.PervasivesModule 中的 at_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 签名:val print_flush : (unit -> unit)

此外,在 OCaml 代码的调试 session 期间查看它的使用情况,看起来 at_exit 在初始化结束时和每次使用调用结束时都被调用模块。

关于如何执行此操作的任何建议、提示。这将是我在 F# 中的第一次事件。

编辑

以下是我对 Format 模块的了解,应该可以帮助解决这个问题。

Format 模块是一个函数库,用于简单 OCaml 值(例如 int、bool、string)的基本 pretty-print 命令。格式模块具有诸如 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 文档所述的范围。

最佳答案

这应该可以做到:

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!"

关于events - 将 OCaml 转换为 F# : F# equivelent of Pervasives at_exit,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12443361/

相关文章:

javascript - 如何根据event.shiftKey 为DOM 中的元素选择创建事件?

f#序列总和

f# - 为什么 F# 的类型推断如此变化无常?

f# - 如何使用 CustomOperations 和一些让有状态的构建器实现

f# - 在 F#/OCaml 中实现类似快速排序的函数的尾递归版本

c# - 从非标准事件创建 Observable(无 EventArgs/EventHandler)

c# - 如何在 WPF 中的 DataGrid 的 DataGridCheckBoxColumn 中处理鼠标事件(MouseEnter、MouseLeave、MouseMove,..)?

c# - .NET 中是否可以使用 C# 实现基于事件的异步模式而无需多线程?

f# - N元元组与对

list - 笛卡尔积类型错误