Javier López-de-Lacalle
2011-Mar-24 09:03 UTC
[R] Extract the names of the arguments in an "expression"
Hi everybody: I need to get the names of the arguments in an object of class "expression". I've got the following expression:> x <- expression(rho * cos(omega))Is there any function or procedure that returns the names of the arguments (in the example: "rho" and "omega")? I tried a rough approach implemented in the function expr.args() shown below. As the function eval() needs to get access to those arguments, a possible approach is as follows: 1) apply eval() to the expression "x" within an empty environment; 2) get the variable names from the character string containing the error message that will be returned: "Error in eval(expr, envir, enclos) : object 'rho' not found"; 3) assign a value to the first identified variable, "rho", and apply eval() again until the expression is evaluated and no error returned. There are some pitfalls in this approach, expr.args(): i) it is a recursive procedure (I guess there must be a more efficient approach); ii) it does not work if some of the arguments, for instance 'rho', exist in the workspace. Despite a new environment is created to evaluate the expression, objects are also searched in the parent environment. The search should somehow stick to the new environment (called 'tmpe' in expr.args()); iii) it does not work if the name of an argument coincides with the name of a function (for instance 'gamma'). Is there any function to do this task? If not, I would appreciate some guidance to improve the function expr.args().> expr.args <- function(x){ cond <- is.expression(x) if (cond) { tmpe <- new.env() } else return() while (cond) { ref <- try(eval(x, envir = tmpe), silent = TRUE) if (cond <- (class(ref) == "try-error")) { if (length(grep("not found", ref[1])) > 0) { aux <- substr(ref, regexpr("object ", ref) + 8, regexpr(" not found", ref) - 2) assign(as.character(aux), 1, envir = tmpe) } else stop("expression could no be evaluated but a missing variable was not identified.") } } ls(envir = tmpe) } Many thanks. javi
Duncan Murdoch
2011-Mar-24 12:02 UTC
[R] Extract the names of the arguments in an "expression"
On 11-03-24 5:03 AM, Javier L?pez-de-Lacalle wrote:> Hi everybody: > > I need to get the names of the arguments in an object of class "expression". > I've got the following expression: > >> x<- expression(rho * cos(omega)) > > Is there any function or procedure that returns the names of the arguments > (in the example: "rho" and "omega")?That expression also includes * and cos, which are also objects in R. I presume you would like to restrict the answer to variables in a particular environment, e.g. the global environment, or the caller of your function. The tricky bit in implementing this is that R has fairly rich scoping rules, so rho and omega need not live in the same environment, as long as both are visible where you evaluate that expression. So then how do you distinguish which of the 4 objects you want back?> > I tried a rough approach implemented in the function expr.args() shown > below. As the function eval() needs to get access to those arguments, a > possible approach is as follows: 1) apply eval() to the expression "x" > within an empty environment; 2) get the variable names from the character > string containing the error message that will be returned: > > "Error in eval(expr, envir, enclos) : object 'rho' not found";I think it would be better to examine the expression, not evaluate it. Some expressions have side effects (e.g. plot(rho), or remove(list=ls())), and you may not want those side effects.> > 3) assign a value to the first identified variable, "rho", and apply eval() > again until the expression is evaluated and no error returned. > > There are some pitfalls in this approach, expr.args(): > > i) it is a recursive procedure (I guess there must be a more > efficient approach); > > ii) it does not work if some of the arguments, for instance 'rho', > exist in the workspace. Despite a new environment is created to evaluate the > expression, objects are also searched in the parent environment. The search > should somehow stick to the new environment (called 'tmpe' in expr.args()); > > iii) it does not work if the name of an argument coincides with the > name of a function (for instance 'gamma'). > > Is there any function to do this task? If not, I would appreciate some > guidance to improve the function expr.args().The codetools package has functions to do things like this, though they are aimed at functions and packages, rather than single expressions. I think you want codetools::findGlobals, e.g. f <- function() {} # a dummy function body(f) <- x # containing the expression as its body codetools::findGlobals(f) # prints [1] "*" "cos" "omega" "rho" Duncan Murdoch> >> expr.args<- function(x) > { > cond<- is.expression(x) > if (cond) { > tmpe<- new.env() > } else return() > > while (cond) > { > ref<- try(eval(x, envir = tmpe), silent = TRUE) > if (cond<- (class(ref) == "try-error")) > { > if (length(grep("not found", ref[1]))> 0) > { > aux<- substr(ref, regexpr("object ", ref) + 8, regexpr(" not > found", ref) - 2) > assign(as.character(aux), 1, envir = tmpe) > } else stop("expression could no be evaluated but a missing variable > was not identified.") > } > } > > ls(envir = tmpe) > } > > Many thanks. > > javi > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.
Kenn Konstabel
2011-Mar-24 12:29 UTC
[R] Extract the names of the arguments in an "expression"
I tried this as an exercise and here's what I arrived to: collector <- function(expr){ RES <- list() foo <- function(x) unlist(lapply(x, as.list)) EXPR <- foo(expr) while(length(EXPR) >0){ if(is.symbol(EXPR[[1]])){ RES <- c(RES, EXPR[[1]]) EXPR <- EXPR[-1] next } if(is.atomic(EXPR[[1]])){ EXPR <- EXPR[-1] next } EXPR <- if(length(EXPR)==1) foo(EXPR[[1]]) else c(foo(EXPR[[1]]), EXPR[-1]) } sapply(RES, as.character) } It worked as expected on all 4 or 5 expressions I tried (you could add "unique" to the last line) but it may be safer to use what's already available in the codetools package as Duncan Murdoch suggested. But of course, * and cos in your example are also returned, as well as any extra parentheses, so> collector(expression((1)))# [1] "(" You can however exclude the functions found in e.g. base package ( see ls("package:base", all=TRUE) ) but then, a user-defined variable in your expression may well be called, e.g. "url" or "T", and these are found int the base package. Regards, Kenn 2011/3/24 Javier L?pez-de-Lacalle <javier.lopezdelacalle at ehu.es>:> Hi everybody: > > I need to get the names of the arguments in an object of class "expression". > I've got the following expression: > >> x <- expression(rho * cos(omega)) > > Is there any function or procedure that returns the names of the arguments > (in the example: "rho" and "omega")? > > I tried a rough approach implemented in the function expr.args() shown > below. As the function eval() needs to get access to those arguments, a > possible approach is as follows: 1) apply eval() to the expression "x" > within an empty environment; 2) get the variable names from the character > string containing the error message that will be returned: > > "Error in eval(expr, envir, enclos) : object 'rho' not found"; > > 3) assign a value to the first identified variable, "rho", and apply eval() > again until the expression is evaluated and no error returned. > > There are some pitfalls in this approach, expr.args(): > > ? ? ? ?i) it is a recursive procedure (I guess there must be a more > efficient approach); > > ? ? ? ?ii) it does not work if some of the arguments, for instance 'rho', > exist in the workspace. Despite a new environment is created to evaluate the > expression, objects are also searched in the parent environment. The search > should somehow stick to the new environment (called 'tmpe' in expr.args()); > > ? ? ? ?iii) it does not work if the name of an argument coincides with the > name of a function (for instance 'gamma'). > > Is there any function to do this task? If not, I would appreciate some > guidance to improve the function expr.args(). > >> expr.args <- function(x) > { > ?cond <- is.expression(x) > ?if (cond) { > ? ?tmpe <- new.env() > ?} else return() > > ?while (cond) > ?{ > ? ?ref <- try(eval(x, envir = tmpe), silent = TRUE) > ? ?if (cond <- (class(ref) == "try-error")) > ? ?{ > ? ? ?if (length(grep("not found", ref[1])) > 0) > ? ? ?{ > ? ? ? ?aux <- substr(ref, regexpr("object ", ref) + 8, regexpr(" not > found", ref) - 2) > ? ? ? ?assign(as.character(aux), 1, envir = tmpe) > ? ? ?} else stop("expression could no be evaluated but a missing variable > was not identified.") > ? ?} > ?} > > ?ls(envir = tmpe) > } > > Many thanks. > > javi > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >
Gabor Grothendieck
2011-Mar-24 12:37 UTC
[R] Extract the names of the arguments in an "expression"
2011/3/24 Javier L?pez-de-Lacalle <javier.lopezdelacalle at ehu.es>:> Hi everybody: > > I need to get the names of the arguments in an object of class "expression". > I've got the following expression: > >> x <- expression(rho * cos(omega)) > > Is there any function or procedure that returns the names of the arguments > (in the example: "rho" and "omega")? >Try this:> all.vars(x)[1] "rho" "omega" -- Statistics & Software Consulting GKX Group, GKX Associates Inc. tel: 1-877-GKX-GROUP email: ggrothendieck at gmail.com