我想存储一个OCaml闭包,供以后的外部C库使用。我能够做到以下几点:
<TARGET> = caml_alloc(Wosize_val(<SOURCE>), Tag_val(<SOURCE>));
caml_register_global_root(<TARGET>);
Code_val(<TARGET>) = Code_val(<SOURCE>);
但正如名称&#34;关闭&#34;建议,仅仅复制代码位置是不够的。
如何制作<SOURCE>
答案 0 :(得分:4)
在我们在iOS中使用OCaml的工作中,我们经常需要保存OCaml闭包并稍后调用它们(当连接到CocoaTouch库时)。所以我的代码已经工作多年了。但是,制作一个好的例子太复杂了(它用Objective C编写)。以下是我刚刚撰写的一些代码,它们捕捉了我们正在做的事情的本质。
首先是一些C代码,可以保存一些类型为unit -> unit
的闭包,并允许您稍后按时间顺序索引调用它们。 (这只是一个例子。)
$ cat saveclo.c
#include "caml/mlvalues.h"
#include "caml/memory.h"
#include "caml/callback.h"
static value saved_closures[10];
static int saved_closure_count = 0;
value save_closure(value clo)
{
CAMLparam1(clo);
saved_closures[saved_closure_count] = clo;
caml_register_global_root(&saved_closures[saved_closure_count]);
saved_closure_count++;
CAMLreturn(Val_unit);
}
value call_closure(value index)
{
CAMLparam1(index);
int ix = Int_val(index);
// For simplicity assume closure : unit -> unit
(void) caml_callback(saved_closures[ix], Val_unit);
CAMLreturn(Val_unit);
}
然后一些OCaml代码执行这些功能:
$ cat clo.ml
external save_closure : (unit -> unit) -> unit = "save_closure"
external call_closure : int -> unit = "call_closure"
let save alist =
let howlong () =
Printf.printf "list length %d\n" (List.length alist)
in
save_closure howlong
let call () =
call_closure 1;
call_closure 0
let () =
save [1;2;3;4;5];
save ['a'; 'b'; 'c'; 'd'; 'e'; 'f'];
Gc.full_major();
call ()
测试运行如下:
$ cc -I /usr/local/lib/ocaml -c -o saveclo.o saveclo.c
$ ocamlopt -c clo.ml
$ ocamlopt -o clo clo.cmx saveclo.o
$ ./clo
list length 6
list length 5
$
我认为重点是(a)代表闭包的OCaml对象已经包含了你需要的东西(某种代码引用和数据)。 (b)你不需要复制它,你只需要确保它不会被垃圾收集。 (c)对caml_register_global_root
的调用创建了对闭包的引用,因此GC知道不收集它。
我希望这会有所帮助。如果有人发现此代码存在问题,请告诉我,我将非常乐意纠正错误。但我相信这是正确的。