【问题标题】:Converting OCaml to F#: F# equivelent of Pervasives at_exit将 OCaml 转换为 F#:Pervasives at_exit 的 F# 等效项
【发布时间】:2012-09-08 17:32:29
【问题描述】:

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

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

注册要在程序终止时调用的给定函数。 使用at_exit 注册的函数将在程序执行退出或终止时被调用,无论是正常还是由于未捕获的异常。函数按“后进先出”的顺序调用:最近添加at_exit 的函数首先被调用。

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

我使用 VS 对象浏览器检查了 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 签名:val print_flush : (unit -> unit)

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

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

编辑

以下是我从 Format 模块中学到的一些内容,应该可以解决这个问题。

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 的机制清理队列和状态并再次为下一组命令准备就绪,该机制识别出对格式模块的初始调用的最后一个匹配帧已被删除,从而触发对@987654339 的调用@ 将队列中剩余的命令推出并重新初始化队列和状态。

因此,对print_flush 的调用顺序至关重要,而且似乎超出了 OCaml 文档所述的顺序。

【问题讨论】:

  • 你可以在你的主要方法中放一个finally
  • 另一个想法 - 保留一个类型的单个实例,然后在程序退出时调用析构函数

标签: events f# ocaml


【解决方案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!"

【讨论】:

  • 我还没有测试过这个答案,但是一旦我测试了就会发布结果。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 1970-01-01
  • 2012-09-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多