Hello.
In the writing of my OCaml-R binding, I'm sort of confused when it comes
to the use of the PROTECT and UNPROTECT macros.
Basically, I have C stub functions that are in charge of calling R for
everything. Here's a simple example:
CAMLprim value r_findvar (value symbol) {
/* The findVar function is defined in envir.c. It looks up a symbol
in an environment. */
CAMLparam1(symbol);
CAMLreturn(Val_sexp(findVar(Sexp_val(symbol), R_GlobalEnv)));
}
This simply makes a call to findVar and returns the value to Objective
Caml. It seems to me that I should be writing:
CAMLprim value r_findvar (value symbol) {
/* The findVar function is defined in envir.c. It looks up a symbol
in an environment. */
CAMLparam1(symbol);
SEXP e;
PROTECT(e = findVar(Sexp_val(symbol), R_GlobalEnv));
CAMLreturn(Val_sexp(e));
}
However, as OCaml has its own GC, I'm wondering where to put UNPROTECT.
Many codes I see on the net UNPROTECT the value just after it has been
protected. The rationale, it seems, is that the value is at risk only a
short timeframe after it has been created.
This seems rather curious to me, and I'm wondering if I should not
rather UNPROTECT the value at the moment OCaml's GC says the value is
not needed anymore.
Please tell me which option I should go forward with.
(I'll assume for now that OCaml is monothreaded. I do not believe that R
itself is thread-safe, so I'll first handle this monothreaded case.)
All the best,
I've had success w/ using a reference counting paradigm in which the outside
memory manager calls UNPROTECT_PTR(R_object_); in its destructor.
So, in my case (using c++ ) if objects are allocated on the heap, which
allocate R objects as their backend storage, I don't have to worry about out
of order UNPROTECT calls b/c UNPROTECT_PTR will just put the objects that
c++ destroys on the gc list.
If you are using c as the glue for all your ocaml bindings, they you may
want to have a look at this:
http://github.com/armstrtw/rabstraction
Or the in progress re-write here: http://github.com/armstrtw/RObjects
-Whit
Thanks a lot for these pointers.
UNPROTECT_PTR seems quite interesting. As I understand it, it avoids
caring about protecting and unprotecting in the order the stacks would
expect. This is quite interesting, since I'd like to keep OCaml's GC to
do housekeeping, and not rely on referencing counting.
I'm using C as the glue, but I want it to be as thin as possible. I will
probably not do reference counting in C, for instance. Nevertheless,
there's obviously good ideas in rabstraction/RObjects that I'll adapt.
Thanks a lot.
On Nov 28, 2009, at 7:50 PM, Guillaume Yziquel wrote:
Whit Armstrong a ?crit :
I've had success w/ using a reference counting paradigm in which the outside
memory manager calls UNPROTECT_PTR(R_object_); in its destructor.
So, in my case (using c++ ) if objects are allocated on the heap, which
allocate R objects as their backend storage, I don't have to worry about out
of order UNPROTECT calls b/c UNPROTECT_PTR will just put the objects that
c++ destroys on the gc list.
If you are using c as the glue for all your ocaml bindings, they you may
want to have a look at this:
http://github.com/armstrtw/rabstraction
Or the in progress re-write here: http://github.com/armstrtw/RObjects
-Whit
Thanks a lot for these pointers.
UNPROTECT_PTR seems quite interesting. As I understand it, it avoids caring about protecting and unprotecting in the order the stacks would expect. This is quite interesting, since I'd like to keep OCaml's GC to do housekeeping, and not rely on referencing counting.
FWIW what I think you should be really looking at is R_PreserveObject/R_ReleaseObject. I would suggest looking at the many other R embeddings in other languages that already exist since I don't think you approach is very viable (but I think I expressed that already before).
Cheers,
Simon
I'm using C as the glue, but I want it to be as thin as possible. I will probably not do reference counting in C, for instance. Nevertheless, there's obviously good ideas in rabstraction/RObjects that I'll adapt.
Thanks a lot.
--
Guillaume Yziquel
http://yziquel.homelinux.org/
On Nov 28, 2009, at 7:50 PM, Guillaume Yziquel wrote:
FWIW what I think you should be really looking at is R_PreserveObject/R_ReleaseObject.
OK. Thanks.
I would suggest looking at the many other R embeddings in other languages that already exist since I don't think you approach is very viable (but I think I expressed that already before).
Lisp - the only thing I've seen is a translator:
http://dan.corlan.net/R_to_common_lisp_translator/
I haven't found a binding for Haskell. Nor for Scheme.
Do you know of any bindings of R to functional languages?
since I don't think you approach is very viable (but I think I expressed that already before).
You expressed the sentiment that it would be a very bad idea to bypass
the current API. I would be happy to hear why you would think that a
low-level binding is not possible, or not very viable.
By low-level, I mean a binding that takes hold of R objects without
using symbols all over to reference them. (Using symbols in the formals,
the body or the environment of a closure is fine, for instance, but I'd
like to execute a closure directly, and eventually be able to construct
R closure from OCaml functions).
Please elaborate on the difficulties you perceive. That would be helpful.
On Nov 29, 2009, at 13:57 , Guillaume Yziquel wrote:
Simon Urbanek a ?crit :
On Nov 28, 2009, at 7:50 PM, Guillaume Yziquel wrote:
FWIW what I think you should be really looking at is
R_PreserveObject/R_ReleaseObject.
OK. Thanks.
I would suggest looking at the many other R embeddings in other
languages that already exist since I don't think you approach is
very viable (but I think I expressed that already before).
Lisp - the only thing I've seen is a translator:
http://dan.corlan.net/R_to_common_lisp_translator/
I haven't found a binding for Haskell. Nor for Scheme.
Do you know of any bindings of R to functional languages?
since I don't think you approach is very viable (but I think I
expressed that already before).
You expressed the sentiment that it would be a very bad idea to
bypass the current API. I would be happy to hear why you would think
that a low-level binding is not possible, or not very viable.
By low-level, I mean a binding that takes hold of R objects without
using symbols all over to reference them. (Using symbols in the
formals, the body or the environment of a closure is fine, for
instance, but I'd like to execute a closure directly, and eventually
be able to construct R closure from OCaml functions).
You're talking about two entirely different things -- bypassing the
API is a very bad idea, but it has nothing to do with your last
paragraph. The API gives you access all user-visible aspects of R
which is all you really need for any embedding -- that includes
closure body, evaluation etc. I see no reason why you should ever go
lower than the API since that is unreliable and unsupported and thus
you won't get any help with that (that is IMHO the main reason why you
get no responses here - and I wouldn't expect any). All other
functions are hidden on purpose since they cover internal aspects that
should not be relied upon.
So again, I just think you're operating on the wrong level here -- and
this has nothing to do with the fact that you're binding to a
functional language since the mechanisms are the same regardless of
the languages (that's why Omegahat was used to bind into any random
language that seemed useful). You get more headaches since you have to
decide how to handle closures both ways, but I suspect the practical
solution is to use evaluators on the side where the function is
defined (especially for the R side since it includes non-S-language
code so you simply cannot map it).
If you have suggestions for extending the API, feel free to post them
with exact explanations how in general that extensions could be useful
(general is the key word here - I think so far it was rather to hack
around your way of implementing it). [And FWIW tryEval *is* part of
the API].
Cheers,
Simon
Please elaborate on the difficulties you perceive. That would be
helpful.
You're talking about two entirely different things -- bypassing the API
is a very bad idea, but it has nothing to do with your last paragraph.
It's very good to hear that it's two different things. This has been
quite unclear to me.
The API gives you access all user-visible aspects of R which is all you
really need for any embedding -- that includes closure body, evaluation
etc. I see no reason why you should ever go lower than the API
Because I've been unable to find what exactly applyClosure or eval
requires, when it comes to the structure of the argument LANGSXP. For
example.
since
that is unreliable and unsupported and thus you won't get any help with
that (that is IMHO the main reason why you get no responses here - and I
wouldn't expect any). All other functions are hidden on purpose since
they cover internal aspects that should not be relied upon.
Please let me be clear on my intentions:
-1- I intend to use only the API if possible.
-2- If not possible, I will perhaps use #define USE_RINTERNALS, which as
I understand is not part of the API.
-3- The libR.so with opened symbols is intended only as a replacement of
GDB during development. Unfortunately, as things are not going as easily
as it could, I am, for gdb-like purposes, writing progressively a new
eval / applyClosure duo in OCaml.
The option -3- will not appear in the interface I will release.
In order to discriminate between option -1- and options -1- + -2-, could
you please answer the following question, which I hope falls in the
scope of legitimate questions on this mailing list:
Suppose I have an OCaml (or pure C if you wish) linked list of OCaml
value wrapping SEXP values. Is it possible, using only the API, to
create a LANGSXP / LISTSXP list out of these SEXPs?
I guess this is the crucial point where I hit the limits of the API.
Please confirm or infirm.
So again, I just think you're operating on the wrong level here -- and
this has nothing to do with the fact that you're binding to a functional
language since the mechanisms are the same regardless of the languages
(that's why Omegahat was used to bind into any random language that
seemed useful).
Will look into Omegahat. Not yet very familiar with R userland.
You get more headaches since you have to decide how to
handle closures both ways, but I suspect the practical solution is to
use evaluators on the side where the function is defined (especially for
the R side since it includes non-S-language code so you simply cannot
map it).
Ok. So suppose I have wrapped an anonymous R closure, called op.
This closure takes two arguments, a string, and yields a float.
I therefore need to write a function "eval_this_op" whose type would be:
eval_this_op : (string -> int) R.t -> string R.t -> int R.t
Essentially, eval_this_op takes three arguments, a wrapped anonymous R
closure, an R string, and yields an R integer.
How could you write such an eval_this_op function without first solving
the crucial issue in the above paragraph, which is basically
constructing a LANGSXP out of an anonymous closure and an R string?
If you have suggestions for extending the API, feel free to post them
with exact explanations how in general that extensions could be useful
(general is the key word here - I think so far it was rather to hack
around your way of implementing it). [And FWIW tryEval *is* part of the
API].
Please take into account that OCaml's type system is extremely strong.
"My way of implementing it", as you call it, is essentially the most
natural way to fit in the OCaml paradigm. I must satisfy both OCaml and
R paradigms in order to write a correct binding.
Please note that it is not an embedding in a random application. It aims
to be a full blown binding for general purpose. In OCaml, values are
immutable. Really, really, really immutable. Or they are signals,
immutable abstractions describing a value that changes overtime.
Symbols, variables and such are not welcome. References (~pointers) are
statically typed and *cannot* be type casted. The type checking is so
strong that you should almost never have to throw an exception. This
means avoiding dynamic type-checking everywhere it's possible to avoid.
This means that a function that takes a sexp to yield the underlying
function should not have to raise an exception if the sexp is not a
function. It should therefore not have to dynamically typecheck the sexp
at runtime. This means that you have to enhance the type system to
*statically* declare (or infer) that this sexp is a LANGSXP. Therefore
you have to use a polymorphic type system (somehow ~ C++ templated
types) to say "lang sxp" "list sxp" "sym sxp", etc... You get the idea?
This is not "my way". It's the OCaml way: They like to statically
type-check *everything* , including HTML. Please have a look at section
"Static typing of XHTML with XHTML.M" of
http://ocsigen.org/eliom/manual/1.2.0/1#p1baseprinciples
Do you know why the Swig module for OCaml is virtually unused? Because
the OCaml community does not consider it type-safe enough. And it will
go somehow the same for Haskell.
The "general" aspect of my request therefore concerns bindings to
languages with 'inferred polymorphic static typing'. Please understand
what these languages are about before dismissing my remarks as "my way".
You may not care, you wouldn't be the first.
From Wikipedia: http://en.wikipedia.org/wiki/Objective_Caml
OCaml's static type system eliminates a large class of programmer errors that may cause problems at runtime. However, it also forces the programmer to conform to the constraints of the type system, which can require careful thought and close attention. A type-inferring compiler greatly reduces the need for manual type annotations (for example, the data type of variables and the signature of functions usually do not need to be explicitly declared, as they do in Java). Nonetheless, effective use of OCaml's type system can require some sophistication on the part of the programmer.
Please understand that I take no joy and no fun in being a pain.
If you force me to write a binding that wouldn't be type safe, it would
be unused. This is simply not acceptable to me: I am unfortunately not
willing to waste my time. And will then eventually have to bypass the
API. Please help me avoid that as much as it is possible with these
constraints.
On Nov 30, 2009, at 12:08 , Guillaume Yziquel wrote:
Simon Urbanek a ?crit :
You're talking about two entirely different things -- bypassing the
API is a very bad idea, but it has nothing to do with your last
paragraph.
It's very good to hear that it's two different things. This has been
quite unclear to me.
The API gives you access all user-visible aspects of R which is all
you really need for any embedding -- that includes closure body,
evaluation etc. I see no reason why you should ever go lower than
the API
Because I've been unable to find what exactly applyClosure or eval
requires, when it comes to the structure of the argument LANGSXP.
For example.
LANGSXP is simply a pairlist representing the expression, e.g. to look
at "a+2" expression:
> .Internal(inspect(quote(a+2)))
@1183698 06 LANGSXP g0c0 []
@101080c 01 SYMSXP g0c0 [MARK,gp=0x4000] "+"
@1130394 01 SYMSXP g0c0 [MARK] "a"
@1c384e8 14 REALSXP g0c1 [] (len=1, tl=0) 2
I would suggest you learn more about R first - this is all accessible
at the R/S language level:
> x
a + 2
> x[[1]]
`+`
> x[[2]]
a
> x[[3]]
[1] 2
since that is unreliable and unsupported and thus you won't get any
help with that (that is IMHO the main reason why you get no
responses here - and I wouldn't expect any). All other functions
are hidden on purpose since they cover internal aspects that should
not be relied upon.
Please let me be clear on my intentions:
-1- I intend to use only the API if possible.
-2- If not possible, I will perhaps use #define USE_RINTERNALS,
which as I understand is not part of the API.
-3- The libR.so with opened symbols is intended only as a
replacement of GDB during development. Unfortunately, as things are
not going as easily as it could, I am, for gdb-like purposes,
writing progressively a new eval / applyClosure duo in OCaml.
The option -3- will not appear in the interface I will release.
In order to discriminate between option -1- and options -1- + -2-,
could you please answer the following question, which I hope falls
in the scope of legitimate questions on this mailing list:
Suppose I have an OCaml (or pure C if you wish) linked list of OCaml
value wrapping SEXP values. Is it possible, using only the API, to
create a LANGSXP / LISTSXP list out of these SEXPs?
Of course - see CONS/LCONS.
I guess this is the crucial point where I hit the limits of the API.
Please confirm or infirm.
So again, I just think you're operating on the wrong level here --
and this has nothing to do with the fact that you're binding to a
functional language since the mechanisms are the same regardless of
the languages (that's why Omegahat was used to bind into any random
language that seemed useful).
Will look into Omegahat. Not yet very familiar with R userland.
You get more headaches since you have to decide how to handle
closures both ways, but I suspect the practical solution is to use
evaluators on the side where the function is defined (especially
for the R side since it includes non-S-language code so you simply
cannot map it).
Ok. So suppose I have wrapped an anonymous R closure, called op.
This closure takes two arguments, a string, and yields a float.
I therefore need to write a function "eval_this_op" whose type would
be:
eval_this_op : (string -> int) R.t -> string R.t -> int R.t
Essentially, eval_this_op takes three arguments, a wrapped anonymous
R closure, an R string, and yields an R integer.
How could you write such an eval_this_op function without first
solving the crucial issue in the above paragraph, which is basically
constructing a LANGSXP out of an anonymous closure and an R string?
If you have suggestions for extending the API, feel free to post
them with exact explanations how in general that extensions could
be useful (general is the key word here - I think so far it was
rather to hack around your way of implementing it). [And FWIW
tryEval *is* part of the API].
Please take into account that OCaml's type system is extremely
strong. "My way of implementing it", as you call it, is essentially
the most natural way to fit in the OCaml paradigm. I must satisfy
both OCaml and R paradigms in order to write a correct binding.
Please note that it is not an embedding in a random application. It
aims to be a full blown binding for general purpose. In OCaml,
values are immutable. Really, really, really immutable. Or they are
signals, immutable abstractions describing a value that changes
overtime. Symbols, variables and such are not welcome. References
(~pointers) are statically typed and *cannot* be type casted. The
type checking is so strong that you should almost never have to
throw an exception. This means avoiding dynamic type-checking
everywhere it's possible to avoid. This means that a function that
takes a sexp to yield the underlying function should not have to
raise an exception if the sexp is not a function. It should
therefore not have to dynamically typecheck the sexp at runtime.
This means that you have to enhance the type system to *statically*
declare (or infer) that this sexp is a LANGSXP. Therefore you have
to use a polymorphic type system (somehow ~ C++ templated types) to
say "lang sxp" "list sxp" "sym sxp", etc... You get the idea?
This is not "my way". It's the OCaml way: They like to statically
type-check *everything* , including HTML. Please have a look at
section "Static typing of XHTML with XHTML.M" of
http://ocsigen.org/eliom/manual/1.2.0/1#p1baseprinciples
Do you know why the Swig module for OCaml is virtually unused?
Because the OCaml community does not consider it type-safe enough.
And it will go somehow the same for Haskell.
The "general" aspect of my request therefore concerns bindings to
languages with 'inferred polymorphic static typing'. Please
understand what these languages are about before dismissing my
remarks as "my way". You may not care, you wouldn't be the first.
You're missing my point - "your way" was to hack into the internals of
how R represents SEXPs (going down to each pointer inside the SEXP
headers). None of the above applies to my remark.
Cheers,
Simon
OCaml's static type system eliminates a large class of programmer
errors that may cause problems at runtime. However, it also forces
the programmer to conform to the constraints of the type system,
which can require careful thought and close attention. A type-
inferring compiler greatly reduces the need for manual type
annotations (for example, the data type of variables and the
signature of functions usually do not need to be explicitly
declared, as they do in Java). Nonetheless, effective use of
OCaml's type system can require some sophistication on the part of
the programmer.
Please understand that I take no joy and no fun in being a pain.
If you force me to write a binding that wouldn't be type safe, it
would be unused. This is simply not acceptable to me: I am
unfortunately not willing to waste my time. And will then eventually
have to bypass the API. Please help me avoid that as much as it is
possible with these constraints.
--
Guillaume Yziquel
http://yziquel.homelinux.org/
Because I've been unable to find what exactly applyClosure or eval
requires, when it comes to the structure of the argument LANGSXP. For
example.
LANGSXP is simply a pairlist representing the expression, e.g. to look
at "a+2" expression:
> .Internal(inspect(quote(a+2)))
@1183698 06 LANGSXP g0c0 []
@101080c 01 SYMSXP g0c0 [MARK,gp=0x4000] "+"
@1130394 01 SYMSXP g0c0 [MARK] "a"
@1c384e8 14 REALSXP g0c1 [] (len=1, tl=0) 2
I would suggest you learn more about R first - this is all accessible at
the R/S language level:
> x
a + 2
> x[[1]]
`+`
> x[[2]]
a
> x[[3]]
[1] 2
I've gathered that LANGSXP and LISTSXP are structured in this way. By
reading the header files. Please see:
https://stat.ethz.ch/pipermail/r-devel/2009-November/055813.html
Now to continue one the topic of the top paragraph:
I've tried sending a LANGSXP where the CAR element is a SYMSXP. eval
workd. I've tried sending a LANGSXP where the CAR element is a CLOSXP.
eval doesn't work. This is what I meant about the "structure of the
argument LANGSXP". And it's contained in the link above.
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?
This does not seem documented in R-ints.pdf, R-exts.pdf or R-lang.pdf.
Suppose I have an OCaml (or pure C if you wish) linked list of OCaml
value wrapping SEXP values. Is it possible, using only the API, to
create a LANGSXP / LISTSXP list out of these SEXPs?
Of course - see CONS/LCONS.
Great. That's the kind of fruitful interaction that could have made me
gain a few days and not bypass the API. Thanks.
The "general" aspect of my request therefore concerns bindings to
languages with 'inferred polymorphic static typing'. Please understand
what these languages are about before dismissing my remarks as "my
way". You may not care, you wouldn't be the first.
You're missing my point - "your way" was to hack into the internals of
how R represents SEXPs (going down to each pointer inside the SEXP
headers). None of the above applies to my remark.
Cheers,
Simon
You're also missing my point. "my way" is the only way I've come up with
to examine how to make sure that the static typing system I'm putting in
place fits with the internal structure of SEXPs. I do need to know the
internal structure of sexps and the way they evolve under the influence
of function such as eval, install, applyClosure, in order to statically
type my code. Same link expressing this concern:
https://stat.ethz.ch/pipermail/r-devel/2009-November/055813.html
Documentation is terse on precise structure of sexps. You get
description of individual sexps, not a *precise* description of how they
are assembled, which is what the typing will have to express. Much in
the same spirit as the link below, which I really entice you to read:
http://ocsigen.org/eliom/manual/1.2.0/1#p1baseprinciples
Statically typing the internal structure of assembled sexps is no
different than statically typing XHTML.
Glad that we're heading somewhere...
All the best,
On Nov 30, 2009, at 13:14 , Guillaume Yziquel wrote:
Simon Urbanek a ?crit :
Because I've been unable to find what exactly applyClosure or eval
requires, when it comes to the structure of the argument LANGSXP.
For example.
LANGSXP is simply a pairlist representing the expression, e.g. to
look at "a+2" expression:
.Internal(inspect(quote(a+2)))
@1183698 06 LANGSXP g0c0 []
@101080c 01 SYMSXP g0c0 [MARK,gp=0x4000] "+"
@1130394 01 SYMSXP g0c0 [MARK] "a"
@1c384e8 14 REALSXP g0c1 [] (len=1, tl=0) 2
I would suggest you learn more about R first - this is all
accessible at the R/S language level:
x
a + 2
x[[1]]
`+`
x[[2]]
a
x[[3]]
[1] 2
I've gathered that LANGSXP and LISTSXP are structured in this way.
By reading the header files. Please see:
https://stat.ethz.ch/pipermail/r-devel/2009-November/055813.html
Now to continue one the topic of the top paragraph:
I've tried sending a LANGSXP where the CAR element is a SYMSXP. eval
workd. I've tried sending a LANGSXP where the CAR element is a
CLOSXP. eval doesn't work. This is what I meant about the "structure
of the argument LANGSXP". And it's contained in the link above.
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 ;)).
Small example:
SEXP myEval(SEXP FN, SEXP first_arg) {
return eval(LCONS(FN, CONS(first_arg, R_NilValue)), R_GlobalEnv);
}
> .Call("myEval",function(x) x + 1, 10)
[1] 11
> .Internal(inspect(function(x) x + 1))
@19e376c 03 CLOSXP g0c0 [ATT]
FORMALS:
@19e399c 02 LISTSXP g0c0 []
TAG: @1029840 01 SYMSXP g0c0 [MARK,NAM(2)] "x"
@1007378 01 SYMSXP g0c0 [MARK,NAM(2)] ""
BODY:
@19e3948 06 LANGSXP g0c0 []
@101080c 01 SYMSXP g0c0 [MARK,gp=0x4000] "+"
@1029840 01 SYMSXP g0c0 [MARK,NAM(2)] "x"
@19e1248 14 REALSXP g0c1 [] (len=1, tl=27187120) 1
CLOENV:
@1023c38 04 ENVSXP g0c0 [MARK,NAM(2),gp=0x8000]
ATTRIB:
@19e3750 02 LISTSXP g0c0 []
TAG: @1006ee0 01 SYMSXP g0c0 [MARK,gp=0x4000] "source"
@19e1228 16 STRSXP g0c1 [] (len=1, tl=16806832)
@150cdc8 09 CHARSXP g0c3 [gp=0x20] "function(x) x + 1"
This does not seem documented in R-ints.pdf, R-exts.pdf or R-lang.pdf.
Suppose I have an OCaml (or pure C if you wish) linked list of
OCaml value wrapping SEXP values. Is it possible, using only the
API, to create a LANGSXP / LISTSXP list out of these SEXPs?
Of course - see CONS/LCONS.
Great. That's the kind of fruitful interaction that could have made
me gain a few days and not bypass the API. Thanks.
... or reading R-ext:
"There are a series of small macros/functions to help construct
pairlists and language objects (whose internal structures just differ
by SEXPTYPE. Function CONS(u, v) is the basic building block: is
constructs a pairlist from u followed by v (which is a pairlist or
R_NilValue). LCONS is a variant that constructs a language object.
Functions list1 to list4 construct a pairlist from one to four items,
andlang1 to lang4 do the same for a language object (a function to
call plus zero to three arguments). Function elt and lastElt find the
ith element and the last element of a pairlist, and nthcdr returns a
pointer to the nth position in the pairlist (whose CAR is the nth
item)."
The "general" aspect of my request therefore concerns bindings to
languages with 'inferred polymorphic static typing'. Please
understand what these languages are about before dismissing my
remarks as "my way". You may not care, you wouldn't be the first.
You're missing my point - "your way" was to hack into the internals
of how R represents SEXPs (going down to each pointer inside the
SEXP headers). None of the above applies to my remark.
Cheers,
Simon
You're also missing my point. "my way" is the only way I've come up
with to examine how to make sure that the static typing system I'm
putting in place fits with the internal structure of SEXPs. I do
need to know the internal structure of sexps and the way they evolve
under the influence of function such as eval, install, applyClosure,
in order to statically type my code. Same link expressing this
concern:
No, you don't - you do care what the *types* are (i.e. TYPEOF) and how
they behave, but you should *not* care how they are implemented in the
internals. That is deliberately hidden by the API.
https://stat.ethz.ch/pipermail/r-devel/2009-November/055813.html
Documentation is terse on precise structure of sexps. You get
description of individual sexps, not a *precise* description of how
they are assembled, which is what the typing will have to express.
Hopefully not - again, see above comment.
Cheers,
Simon
Much in the same spirit as the link below, which I really entice you
to read:
http://ocsigen.org/eliom/manual/1.2.0/1#p1baseprinciples
Statically typing the internal structure of assembled sexps is no
different than statically typing XHTML.
Glad that we're heading somewhere...
All the best,
--
Guillaume Yziquel
http://yziquel.homelinux.org/
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 ;)).
Small example:
SEXP myEval(SEXP FN, SEXP first_arg) {
return eval(LCONS(FN, CONS(first_arg, R_NilValue)), R_GlobalEnv);
}
> .Call("myEval",function(x) x + 1, 10)
[1] 11
In the eval function in eval.c, you have:
case LANGSXP:
if (TYPEOF(CAR(e)) == SYMSXP)
/* This will throw an error if the function is not found */
PROTECT(op = findFun(CAR(e), rho));
else
PROTECT(op = eval(CAR(e), rho));
So imagine you have a LANGSXP whose CAR is a CLOSXP, the execution goes
into the last line of the code snippet above. And re-entring eval with a
CLOSXP, the code goes into
tmp = R_NilValue; /* -Wall */
#ifdef Win32
/* This is an inlined version of Rwin_fpreset (src/gnuwin/extra.c)
and resets the precision, rounding and exception modes of a ix86
fpu.
*/
__asm__ ( "fninit" );
#endif
R_Visible = TRUE;
switch (TYPEOF(e)) {
case NILSXP:
case LISTSXP:
case LGLSXP:
case INTSXP:
case REALSXP:
case STRSXP:
case CPLXSXP:
case RAWSXP:
case S4SXP:
case SPECIALSXP:
case BUILTINSXP:
case ENVSXP:
case CLOSXP:
case VECSXP:
case EXTPTRSXP:
so PROTECT(op = eval(CAR(e), rho)) evaluates to R_NilValue.
I figured out that's why evaluating a LANGSXP with CAR a CLOSXP simply
fails.
I'll have a look at the code snippet you gave, since I do not understand
why it doesn't fail the same way mine does.
Thanks a lot.
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 ;)).
Small example:
SEXP myEval(SEXP FN, SEXP first_arg) {
return eval(LCONS(FN, CONS(first_arg, R_NilValue)), R_GlobalEnv);
}
.Call("myEval",function(x) x + 1, 10)
[1] 11
In the eval function in eval.c, you have:
case LANGSXP:
if (TYPEOF(CAR(e)) == SYMSXP)
/* This will throw an error if the function is not found
*/
PROTECT(op = findFun(CAR(e), rho));
else
PROTECT(op = eval(CAR(e), rho));
So imagine you have a LANGSXP whose CAR is a CLOSXP, the execution
goes into the last line of the code snippet above.
And re-entring eval with a CLOSXP, the code goes into
tmp = R_NilValue; /* -Wall */
#ifdef Win32
/* This is an inlined version of Rwin_fpreset (src/gnuwin/extra.c)
and resets the precision, rounding and exception modes of a
ix86
fpu.
*/
__asm__ ( "fninit" );
#endif
R_Visible = TRUE;
switch (TYPEOF(e)) {
case NILSXP:
case LISTSXP:
case LGLSXP:
case INTSXP:
case REALSXP:
case STRSXP:
case CPLXSXP:
case RAWSXP:
case S4SXP:
case SPECIALSXP:
case BUILTINSXP:
case ENVSXP:
case CLOSXP:
case VECSXP:
case EXTPTRSXP:
so PROTECT(op = eval(CAR(e), rho)) evaluates to R_NilValue.
Nope, it simply evaluates to itself (with ref count increased) - see
tmp = e; ..; return(tmp).
I figured out that's why evaluating a LANGSXP with CAR a CLOSXP
simply fails.
Wrong ;). A closure is a constant like any other object so it
evaluates to itself.
Cheers,
Simon
I'll have a look at the code snippet you gave, since I do not
understand why it doesn't fail the same way mine does.
Thanks a lot.
--
Guillaume Yziquel
http://yziquel.homelinux.org/