From guillaume.yziquel at citycable.ch  Tue Dec  1 10:33:46 2009
From: guillaume.yziquel at citycable.ch (Guillaume Yziquel)
Date: Tue, 01 Dec 2009 10:33:46 +0100
Subject: [Rd] PROTECT and OCaml GC.
In-Reply-To: <7971A8AF-189B-4955-9E62-4E118E594792@r-project.org>
References: <4B11B75C.9070806@citycable.ch>
	<8ec76080911281625q5d5b8824hefb14af9b23d29f0@mail.gmail.com>
	<4B11C55E.2060909@citycable.ch>
	<F11B6C18-26EC-41F8-9EEB-A614D16945AC@r-project.org>
	<4B12C417.1050308@citycable.ch>
	<65D411CD-34C3-4B89-8FF0-98C9BD7613FB@r-project.org>
	<4B13FC0F.40604@citycable.ch>
	<F60B92C3-5989-404C-8FEB-1B6002824449@r-project.org>
	<4B140B7A.2080102@citycable.ch>
	<0A1D8E9D-0BD6-40F7-B98C-59075CE04E49@r-project.org>
	<4B143401.4050607@citycable.ch>
	<7971A8AF-189B-4955-9E62-4E118E594792@r-project.org>
Message-ID: <4B14E2FA.8000302@citycable.ch>

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/



[Rd] PROTECT and OCaml GC.
Guillaume Yziquel