我正在转换 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_box
和print_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/