Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get information about a promise without evaluating the promise

Tags:

r

In a fresh R session, I created a promise z, the vectors x and y, and a function obj.info.

delayedAssign("z", logical(5))
x <- 1:100
y <- rnorm(4e3L)
obj.info <- function(envir = .GlobalEnv){
    ls <- ls(envir)
    obj <- sapply(ls, get)
    FUN <- function(x){
        c(type = class(x), length = length(x), size = object.size(x))
    }
    noquote(t(sapply(obj, FUN)))
} 

In RStudio, the Global Environment table is as expected, with the unevaluated promise included.
This is exactly what I want to duplicate


enter image description here


A call to obj.info() returns the following table.

obj.info()
#          type     length size 
# obj.info function 1      13872
# x        integer  100    440  
# y        numeric  4000   32040
# z        logical  5      72 

The problem is that z has been evaluated in the process, and I didn't want that to happen quite yet. All I want is the information about z.

At first, I figured get was causing this, but evaluation of z also occurs if I call class on the ls() objects before calling get. The result I want has

# z        promise  0      0

for the promised object z.

Is the table in the RStudio window something is easily accessible from the console? And if so, can we get it without evaluating z? Something like the following ls.str table (and others) that can be deparsed would be ideal.

capture.output(ls.str())
# [1] "obj.info : function (envir = .GlobalEnv)  "              
# [2] "x :  int [1:100] 1 2 3 4 5 6 7 8 9 10 ..."               
# [3] "y :  num [1:4000] -0.277 -0.431 -0.143 -0.218 -0.846 ..."
# [4] "z :  logi [1:5] FALSE FALSE FALSE FALSE FALSE"    

Or even if there's a way to run this condition through an if statement, something like

if( x is a promise ) { do not evaluate it, but get its information }

I'm running RStudio Version 0.98.994

like image 974
Rich Scriven Avatar asked Aug 05 '14 20:08

Rich Scriven


1 Answers

Hadley has a simple Rcpp implementation of the relevant code in his pryr library.

The relevant code snippet is:

// [[Rcpp::export]]
bool is_promise2(Symbol name, Environment env) {
  SEXP object = Rf_findVar(name, env);

  return (TYPEOF (object) == PROMSXP);
}

// [[Rcpp::export]]
SEXP promise_code(Symbol name, Environment env) {
  SEXP object = Rf_findVar(name, env);
  return PRCODE(object);
}
// [[Rcpp::export]]
SEXP promise_value(Symbol name, Environment env) {
  SEXP object = Rf_findVar(name, env);
  return PRVALUE(object);
}

Here’s how this can be used:

Rcpp::sourceCpp('promise.cpp')
delayedAssign("z", logical(5))
is_promise2('z', environment())
# [1] TRUE
promise_code('y', environment())
# logical(5)

However, sourceCpp always recompiles the code, which is inefficient. Rcpp sources are normally used as part of a package.

like image 148
Konrad Rudolph Avatar answered Sep 29 '22 13:09

Konrad Rudolph