Re: [Rd] PROTECT and OCaml GC.

From: Guillaume Yziquel <guillaume.yziquel_at_citycable.ch>
Date: Tue, 01 Dec 2009 10:33:46 +0100

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/

______________________________________________
R-devel_at_r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Received on Tue 01 Dec 2009 - 09:39:35 GMT

This archive was generated by hypermail 2.2.0 : Tue 01 Dec 2009 - 12:10:54 GMT