Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using substitute to do variable substitutions inside R expressions

I would like to use substitute() to do variable substitutions inside expressions, without evaluating the expressions. For example, I have:

expr1 <- expression(if(x){
    return(y)
} else {
    return(z)
})

What I would like to do is get the following result assigned to "expr1":

expression(if(cos(x)){
    return(y)
} else {
    return(z)
 })

By doing something like this:

expr2 <- substitute(expr1, list(x=cos(x)))

But that doesn't work, since substitute doesn't evaluate it's first argument. And so I just get back the original variable:

expr1

Now here it says that to do substitutions in an expression assigned to a variable, I have to execute substitute() twice, followed by eval(), like this:

expr2 <- eval(substitute(substitute(e, list(x = cos(x))), list(e = expr1)))

When I execute this statement, I do get an expression assigned to "expr2", but it doesn't contain the required substitution:

expression(if (x) {
    return(y)
} else {
    return(z)
})

What syntax can I apply to "expr1" so that I get the result I would like assigned to "expr2", namely:

expression(if (cos(x)) {
    return(y)
} else {
    return(z)
})
like image 953
user3990797 Avatar asked Jul 13 '15 01:07

user3990797


1 Answers

This appears to do the trick

do.call('substitute', list(expr1[[1]], list(x=quote(cos(x)))))
# if (cos(x)) {
#     return(y)
# } else {
#     return(z)
# }

First I use do.call to pass the unevaluated expression as a parameter to substitute() rather than a double-substitute. Secondly, expression() is really like a container object. You're really interested in just changing the code block of the first element of your expression. You could have avoided the expression() and just used quote() to avoid the "unboxing"

expr2 <- quote(if(x){ return(y) } else { return(z) })
do.call('substitute', list(expr2, list(x=quote(cos(x)))))

Both of these will return a class of type "if". If you need to, you can wrap it in an as.expression().

as.expression(do.call('substitute', list(expr1[[1]], list(x=quote(cos(x))))))
# expression(if (cos(x)) {
#     return(y)
# } else {
#     return(z)
# })
like image 179
MrFlick Avatar answered Oct 19 '22 22:10

MrFlick