Le 14 févr. 2014 à 16:40, luke-tier...@uiowa.edu a écrit :

> On Tue, 11 Feb 2014, Romain Francois wrote:
> 
>> Hello,
>> 
>> We have something very similar to your while loop in dplyr.
>> https://github.com/hadley/dplyr/blob/02a609310184d003c2ae9e0c013bfa69fa4d257a/inst/include/tools/DataDots.h#L15
>> 
>> because we need to know exactly in which environment a promise is supposed 
>> to be evaluated, even though we might combine standard R evaluation with an 
>> alternative faster engine. this is the basis of what we called hybrid 
>> evaluation.
>> 
>> 
>> For future work, I also have the while loop in the Promise class in Rcpp11, 
>> so that when you create a Promise in Rcpp11, its .environment() method gives 
>> you what you expect.
>> https://github.com/romainfrancois/Rcpp11/blob/master/inst/include/Rcpp/Promise.h#L14
>> 
>> So, this is something I find useful, although I’m not sure we are supposed 
>> to mess with promises.
> 
> No you are not :-)

Most of what we do with them is consult them. So whenever the better approach 
you mention becomes available in R, we can update the Promise class and change 
how to get access to the expression and the environment in which it will be 
eventually evaluated. 

Not the first time I get « you are not supposed to use that because we might 
change it ». Experience is that that sort of changes are relatively slow to 
happen, so are easy to adapt to. 

Romain

> Promises are an internal mechanism for implementing lazy
> evaluation. They are convenient but also very inefficient, so they may
> very well go away when a better approach becomes available.  What will
> not go away is the functionality they provide -- bindings with
> deferred evaluations, an expression/code for the evaluation, and an
> environment (until the evaluation happens). If you build on those
> concepts you will be more future proof than if you assume there will
> be an internal promise object.
> 
> Best,
> 
> luke
> 
>> 
>> Romain
>> 
>> Le 11 févr. 2014 à 19:02, Michael Lawrence <lawrence.mich...@gene.com> a 
>> écrit :
>> 
>>> Hi all,
>>> 
>>> It seems that there is a use case for obtaining the environment for the
>>> "top" promise. By "top", I mean following the promise chain up the call
>>> stack until hitting a non-promise.
>>> 
>>> S4 data containers often mimic the API of base R data structures. This
>>> means writing S4 methods for functions that quote their arguments, like
>>> with() and subset(). The methods package directly forwards any arguments
>>> not used for dispatch, so substitute(subset) is able to resolve the
>>> original quoted argument (this is not the case for naively written
>>> wrappers).  The problem then becomes figuring out the environment in which
>>> to evaluate the expression.
>>> 
>>> Consider:
>>> 
>>> setClass("A", representation(df = "data.frame"))
>>> 
>>> setMethod("subset", "A", function(x, subset) {
>>> env <- parent.frame(2)
>>> x@df <- x@df[eval(substitute(subset), x@df, env),,drop=FALSE]
>>> x
>>> })
>>> 
>>> dropLowMpg <- function(x, cutoff=20) {
>>> invisible(subset(x, mpg > cutoff))
>>> }
>>> 
>>> a <- new("A", df=mtcars)
>>> dropLowMpg(a)
>>> 
>>> The above works just fine, because we figured out that we need to evaluate
>>> in the grand-parent frame to avoid the frame of the generic call. But now
>>> let's assume A has a subclass B, and subset,B delegates to subset,A via
>>> callNextMethod(). The call stack is different, and our assumption is
>>> invalid.
>>> 
>>> setClass("B", representation(nrow="integer"), contains="A")
>>> setMethod("subset", "B", function(x, ...) {
>>> ans <- callNextMethod()
>>> ans@nrow <- nrow(ans@df)
>>> ans
>>> })
>>> b <- new("B", df=mtcars)
>>> dropLowMpg(b)
>>> Error in eval(expr, envir, enclos) (from #3) : object 'cutoff' not found
>>> 
>>> We can fix this with a simple C function:
>>> SEXP top_prenv(SEXP nm, SEXP env)
>>> {
>>> SEXP promise = findVar(nm, env);
>>> while(TYPEOF(promise) == PROMSXP) {
>>>   env = PRENV(promise);
>>>   promise = PREXPR(promise);
>>> }
>>> return env;
>>> }
>>> 
>>> With R wrapper:
>>> top_prenv <- function(x) {
>>> .Call2("top_prenv", substitute(x), parent.frame())
>>> }
>>> 
>>> Then this works (need to set subset,B again to reset cache):
>>> 
>>> setMethod("subset", "A", function(x, subset) {
>>> env <- top_prenv(subset)
>>> x@df <- x@df[eval(substitute(subset), x@df, env),,drop=FALSE]
>>> x
>>> })
>>> setMethod("subset", "B", function(x, ...) {
>>> ans <- callNextMethod()
>>> ans@nrow <- nrow(ans@df)
>>> ans
>>> })
>>> 
>>> b <- new("B", df=mtcars)
>>> dropLowMpg(b)
>>> 
>>> Would this be a useful addition to R? Is there a better way to solve this
>>> issue? We're using this successfully in the IRanges package now, but we'd
>>> like to avoid dealing with the internal details of R, and this is something
>>> that could be of general benefit.
>>> 
>>> Thanks,
>>> Michael
>>> 
>>>     [[alternative HTML version deleted]]
>>> 
>>> ______________________________________________
>>> R-devel@r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>> 
>> ______________________________________________
>> R-devel@r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>> 
> 
> -- 
> Luke Tierney
> Chair, Statistics and Actuarial Science
> Ralph E. Wareham Professor of Mathematical Sciences
> University of Iowa                  Phone:             319-335-3386
> Department of Statistics and        Fax:               319-335-3017
>   Actuarial Science
> 241 Schaeffer Hall                  email:   luke-tier...@uiowa.edu
> Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to