在 OCaml 库中仅运行一次代码

发布于 2024-11-05 14:27:14 字数 706 浏览 3 评论 0原文

我正在编写一个 OCaml 库,其中包含一些初始化代码,这些代码在使用该库的程序的生命周期内只需要运行一次(并存储一些将在程序的生命周期中持续存在的状态,但只能在库本身内使用),以及一些仅在使用该库的程序退出时才需要运行的清理代码。

如果相关的话,我的库由两部分组成:低级 C 库的接口,以及一些使编程更容易的高级内容。我可以在 C 的某个地方做我需要的事情吗?理想情况下,我的用户不会关心它是如何实现的,他们永远不会看到 C 位。

在 Python 中,我会通过在 import 上运行代码来实现此目的,但 OCaml 的 open 实际上并不运行任何东西,它只是对模块命名空间进行糖化处理,然后是 Python 的 atexit< /code>,但我找不到 Ocaml 等效项。

我考虑过的一种方法是将我的库构建为一个“框架”,但我认为它的重要性不足以保证这种过度设计的方法。谢谢!

更新:好的,我想明白了。我正在使用 C 代码来处理退出时的清理,并且我对代码进行了一些修改,因此在 C 端有一个指向全局状态的指针,

它会出现在我的库中,我现在 ?

let global_env = env_create ()

当主程序打开时,它确实运行...但是如何运行呢

I am writing an OCaml library that has some initialization code that needs to be run only once during the lifetime of the program using the library (and store some state that will persist for the lifetime of the program, but only be used within the library itself), and some cleanup code that needs to be run only as the program using the library exits.

If it is relevant, my library is two parts: an interface to a low-level C library, and some higher-level stuff to make programming with it easier. Can I do what I need somewhere in the C? Ideally my users wouldn't care how it was implemented, they would never see the C bits.

In Python I would do this by running code on import but OCaml's open doesn't actually run anything, it just sugars the module namespace, and then Python's atexit, but I can't find the Ocaml equivalent.

One approach I have considered is structuring my library as a "framework" but I don't think it's important enough to warrant such an over-engineered approach. Thanks!

UPDATE: OK got it - I think. I am using the C code to handle the cleanup on exit and I have monkeyed with the code a bit so there is a pointer to the global state on the C side

It would appear that in my library I now have

let global_env = env_create ()

And when it is open'd by the main program, this does get run... But how?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

擦肩而过的背影 2024-11-12 14:27:14

请注意,这可以在 OCaml 端使用 Pervasives.at_exit 和顶级语句来创建环境并安装清理代码:

let env = init ()
let cleanup () = do_clean env
let () = at_exit cleanup 

let f x = f_stub env x

顶级语句在模块加载(无论您最终是否使用)和模块加载时执行按照您在链接时指定的顺序(因此依赖于其他模块的模块可以保证在轮到它们时初始化它们的依赖项),请参阅 ocamlc 手册。这意味着顶级语句将在您尝试访问模块之前执行。这不是打开模块的问题,open 只是一种(糟糕的)语法便利。

如果您希望当且仅当模块的函数最终被调用时才执行初始化代码,请使用惰性值:

let env = lazy (init ())
let cleanup () = if Lazy.lazy_is_val env then (do_clean env) else () 
let () = at_exit cleanup

let f x = f_stub (Lazy.force env) x

顺便说一句。不要忘记记录线程安全所产生的问题......

Note that this can be done on the OCaml side with Pervasives.at_exit and top-level statements to create the environment and install the cleanup code :

let env = init ()
let cleanup () = do_clean env
let () = at_exit cleanup 

let f x = f_stub env x

The toplevel statements are executed when the module is loaded (whether you eventually use it or not) and modules are loaded in the order you specified them at link time (thus modules depending on others are guaranteed that their dependencies are initialized when their turn comes), see "Arguments ending with .cmo" in the manual of ocamlc. This entails that toplevel statements will have executed before you try to access the module. It's not a matter of opening the module, open is just a (bad) syntactic convenience.

If you want the init code to be performed if and only if a function of the module eventually gets called use a lazy value :

let env = lazy (init ())
let cleanup () = if Lazy.lazy_is_val env then (do_clean env) else () 
let () = at_exit cleanup

let f x = f_stub (Lazy.force env) x

Btw. don't forget to document the resulting issues with thread-safety...

无法回应 2024-11-12 14:27:14

正如 let x = function ... 定义了一个从该点可用的函数 x
从此以后,您的 let global_env = ... 定义了一个值 global_env 。如果你不这样做
需要 env_create 的返回值,因为您运行它只是为了它的副作用,
你也可以在末尾(说实话,任何地方)提到 env_create ()
ml 文件。
在这种情况下,我会执行 let _ = env_create () ,我认为这更明确。

编辑:R指出以下是错误的:
“要纯粹用 C 语言实现,我认为 _init_fini 是需要寻找的东西。”
正如HOWTO中所解释的,它确实已被弃用,现在应该完成通过属性。

Just as let x = function ... defines a function x that is available from that point
onwards, your let global_env = ... defines a value global_env that is. If you don't
need the return value of env_create, because you run it only for it's side effects,
you could also just mention env_create () at the end (to be honest, anywhere) of the
ml file.
In this case I would do let _ = env_create () though, which I think is more explicit.

EDIT: R pointed out that the following is wrong:
"To do it purely in C, I think that _init and _fini are the things to look for."
As explained in this HOWTO, it is indeed deprecated and should now be done via attributes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文