[Rd] PROTECT and OCaml GC.
Guillaume Yziquel
guillaume.yziquel at citycable.ch
Tue Dec 1 10:33:46 CET 2009
Simon Urbanek a écrit :
>
> On Nov 30, 2009, at 16:07 , Guillaume Yziquel wrote:
>
>> Simon Urbanek a écrit :
>>>>
>>>> And it goes then to my other question: How can you pass to eval a
>>>> LANGSXP where the CAR is an *anonymous* function, no SYMSXP involved?
>>> You just pass it as value of the call. I suspect the reason it
>>> doesn't work is in your code, not in the facility (note that the link
>>> above is useless since the construction is mystery - if you were
>>> constructing it right, it would work ;)).
The small example you gave just works out fine with the framework I've
been building so far:
> yziquel at seldon:~$ ocaml-batteries
> Objective Caml version 3.11.1
>
> _________________________________
> | | | |
> [| + | | Batteries Included - |
> |_______|_|_______________________|
> _________________________________
> | | | |
> | - Type '#help;;' | | + |]
> |_______________________|_|_______|
>
>
> # #require "R.interpreter";;
> # let show x = R.Pretty.t_of_sexp x;;
> val show : R.sexp -> R.PrettyTypes.t = <fun>
> # open R.PrettyTypes;;
This is administrativia.
> # let r_f_unevaluated = R.parse_sexp "function(x) x + 1";;
> val r_f_unevaluated : R.sexp = <abstr>
> # let r_f = R.eval_langsxp r_f_unevaluated;;
> val r_f : R.sexp = <abstr>
> # show r_f_unevaluated;;
> - : R.PrettyTypes.t =
> CALL (SYMBOL (Some ("function", SPECIAL)),
> [(NULL, LIST [(ARG "x", PLACE)]);
> (NULL,
> CALL (SYMBOL (Some ("+", BUILTIN)), [(NULL, ARG "x"); (NULL, Unknown)]));
> (NULL, STRINGS ["function(x) x + 1"])])
> # show r_f;;
> - : R.PrettyTypes.t =
> CLOSURE
> {formals = LIST [(ARG "x", PLACE)];
> clos_env = ENV {frame = NULL; hashtab = NULL}}
So after evaluating the parsed output of "function(x) x + 1", you indeed
get a pure closure. So far so good.
> # let x = R.parse_sexp "11";;
> val x : R.sexp = <abstr>
> # R.sexptype x;;
> - : R.sexptype = R.RealSxp
Here's the argument, 11.
> # let call = R.langsxp_of_list [r_f; x] 2;;
> val call : R.lang R.sxp = <abstr>
> # show call;;
> - : R.PrettyTypes.t =
> CALL
> (CLOSURE
> {formals = LIST [(ARG "x", PLACE)];
> clos_env = ENV {frame = NULL; hashtab = NULL}},
> [(NULL, Unknown)])
Here's the call that is built out of the closure and 11. For
construction details, the C function is given at the bottom.
> # let y = R.eval_langsxp call;;
> val y : R.sexp = <abstr>
And it gets correctly evaluated. So this is fine. In fact, it works on
the majority of the things I try. So I guess I've been building it fine.
What's not fine is the following, from the quantmod package:
> # let s = R.string "YHOO";;
> val s : string R.t = <abstr>
s is a STRSXP vector containing only one string: "YHOO".
> # let g = R.force (R.symbol "getSymbols");;
> val g : 'a R.t = <abstr>
g is the getSymbols function from quantmod. From the help(getSymbols)
invocation:
> Usage:
>
> getSymbols(Symbols = NULL,
> env = .GlobalEnv,
> reload.Symbols = FALSE,
> verbose = FALSE,
> warnings = TRUE,
> src = "yahoo",
> symbol.lookup = TRUE,
> auto.assign = TRUE,
> ...)
So I try out getSymbols("YHOO"). It works out fine, and returns silently
in the R toplevel.
But, from my binding:
> # R.eval_langsxp (R.langsxp_of_list [g; s] 2);;
> Erreur dans as.character(sc[[1]]) :
> cannot coerce type 'closure' to vector of type 'character'
> Exception: Failure "OCaml-R error in r_eval_sxp C stub.".
Here are the values of s and g:
> # show s;;
> - : R.PrettyTypes.t = STRINGS ["YHOO"]
> # show g;;
> - : R.PrettyTypes.t =
> CLOSURE
> {formals =
> LIST
> [(ARG "Symbols", NULL); (ARG "env", Unknown);
> (ARG "reload.Symbols", Unknown); (ARG "verbose", Unknown);
> (Unknown, Unknown); (ARG "src", STRINGS ["yahoo"]);
> (ARG "symbol.lookup", Unknown); (ARG "auto.assign", Unknown);
> (ARG "...", PLACE)];
> clos_env = ENV {frame = NULL; hashtab = Unknown}}
For the sake of exhaustivity, here's the C functions that I wrote to
make function calls:
> CAMLprim value r_eval_sxp (value sexp_list) {
> CAMLparam1(sexp_list);
> SEXP e;
> int error = 0;
> PROTECT(e = R_tryEval(Sexp_val(sexp_list), R_GlobalEnv, &error));
> UNPROTECT(1);
> if (error) caml_failwith("OCaml-R error in r_eval_sxp C stub.");
> CAMLreturn(Val_sexp(e));
> }
and
> CAMLprim value r_langsxp_of_list (value l, value n) {
> CAMLparam2(l, n);
> CAMLlocal1(l_cursor);
> SEXP s, t;
> PROTECT(t = s = Rf_allocList(Int_val(n)));
> SET_TYPEOF(s, LANGSXP);
> int first_time = 1;
> l_cursor = l;
> while (l_cursor && Is_block(l_cursor)) {
> if (first_time) {first_time = 0;} else {t = CDR(t);}
> SETCAR(t, Sexp_val(Field(l_cursor, 0)));
> l_cursor = Field(l_cursor, 1);
> }
> UNPROTECT(1);
> CAMLreturn(Val_sexp(s));
> }
So I'm almost constructing LANGSXP lists in the way you do.
One last thing, concerning the use of promises. If I do install,
findVar, without forcing the resulting promise, and then construct the
call, I get a failure:
> # R.eval_langsxp (R.langsxp_of_list [(R.symbol "str"); (R.symbol "lm")] 2);;
> Erreur dans function (object, ...) :
> function générique incorrecte dans 'UseMethod'
> Exception: Failure "OCaml-R error in r_eval_sxp C stub.".
If I force the promises:
> # R.eval_langsxp (R.langsxp_of_list [(R.force (R.symbol "str")); (R.force (R.symbol "lm"))] 2);;
> function (formula, data, subset, weights, na.action, method = "qr",
> model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE,
> contrasts = NULL, offset, ...)
> - : R.sexp = <abstr>
It works.
So you may say that "I'm not constructing it right", I still believe
that describing precisely what kind of arguments is accepted by eval
would a good thing.
All the best,
--
Guillaume Yziquel
http://yziquel.homelinux.org/
More information about the R-devel
mailing list