Nel nostro lavoro sull'utilizzo di OCaml in iOS, spesso è necessario salvare le chiusure OCaml e chiamarle in un secondo momento (quando si interfacciano alle librerie CocoaTouch). Quindi ho un codice che funziona da anni. Tuttavia, è troppo complicato per fare un buon esempio (ed è scritto nell'Obiettivo C). Ecco un codice che ho appena scritto che cattura l'essenza di ciò che stiamo facendo.
Prima un codice C che consente di risparmiare un certo numero di chiusure di tipo unit -> unit
e consente di chiamarle in un secondo momento in base all'indice cronologico. (E 'solo un esempio.)
$ 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);
}
Poi certo codice OCaml che esercita queste funzioni:
$ 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()
Un test simile a questa:
$ 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
$
penso che i punti salienti sono (a) l'oggetto OCaml che rappresenta una chiusura contiene già ciò di cui hai bisogno (un codice di riferimento di qualche tipo e i dati). (b) Non è necessario copiarlo, è sufficiente assicurarsi che non venga raccolta la garbage collection. (c) La chiamata a caml_register_global_root
crea un riferimento alla chiusura in modo che il GC sappia di non raccoglierlo.
Spero che questo sia utile. Se qualcuno vede problemi con questo codice, fammelo sapere e sarò più che felice di correggere gli errori. Ma credo sia corretto.
fonte
2014-04-23 19:10:54
Quando dici "dopo", intendi più tardi nello stesso processo? Se è così, non è necessario copiare la chiusura (mi sembra). Devi solo assicurarti che non sia GCed prima di volerlo usare. Che cosa stai facendo con 'caml_register_global_root'. –
Potresti per favore fare una risposta dettagliata, quindi posso accettarlo? – choeger
Felice di fare questo :-) È tardi qui a GMT - 7, dovrà essere domani. Saluti, –