as.name and namespaces
Hi Pat,
You could use substitute(),
> mycall <- quote(list(lm(Y ~ x1), lm(Y ~ x2)))
> do.call("substitute", list(mycall, list(lm=quote(stats::lm))))
list(stats::lm(Y ~ x1), stats::lm(Y ~ x2))
The do.call is necessary because substitute() does not evaluate
its first argument and we want 'mycall' evaluated to become
the call to list(...) before substitute works on it.
substitute replaces all instances of a name in an expression.
bquote lets you be more selective (only names in .() get replaced):
> mycall2 <- quote(list(lm(Y ~ x1), .(lm)(Y ~ x2)))
> do.call("bquote", list(mycall2, list(lm=quote(stats::lm), list=quote(base::list))))
list(lm(Y ~ x1), stats::lm(Y ~ x2))
S+'s substitute() has an evaluate=FALSE/TRUE argument to control
whether its first argument is evaluated thus letting you avoid do.call():
S+> mycall <- quote(list(lm(Y ~ x1), lm(Y ~ x2)))
S+> substitute(mycall, list(lm=quote(stats::lm)), evaluate=TRUE)
list(stats::lm(Y ~ x1), stats::lm(Y ~ x2))
It is much harder if you want to find and replace expressions more general
than name, e.g., changing "stats::lm" to "lm" or "log(x+1)" to "logp1(x)" .
package::codetools and package::compiler might help. I have used rapply()
in S+ for this sort of thing but R's rapply() does not work on functions:
S+> f <- function(x, y) exp(log(x+1) + log(abs(y)+1) + log(z))
S+> fNew <- rapply(f, how="replace", classes="call",
function(e) {
if (identical(e[[1]], quote(log)) && is.call(logArg <- e[[2]])) {
if (identical(logArg[[1]], quote(`+`)) && identical(logArg[[3]], 1)) {
e <- call("logp1", logArg[[2]])
}
}
e
})
S+> fNew
function(x, y)
exp(logp1(x) + logp1(abs(y)) + log(z))
The is pretty ugly code but it did help us quickly install optimizations in
a large mass of code.
Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com
-----Original Message----- From: r-devel-bounces at r-project.org [mailto:r-devel-bounces at r-project.org] On Behalf Of Patrick Burns Sent: Wednesday, April 24, 2013 2:30 AM To: Duncan Murdoch Cc: r-devel Subject: Re: [Rd] as.name and namespaces Here is an example problem:
> mycall <- expression(lm(Y ~ x))[[1]] > mycall
lm(Y ~ x)
> newname <- "stats::lm"
> desiredResult
stats::lm(Y ~ x) I've solved the problem in the kludgy way of deparsing, fixing the string and then parsing. I like Duncan's third method, but it seems like it assumes the solution. Moving functions around is unappetizing for my use -- this is for testing and keeping things as faithful to real use is a good thing. Pat On 23/04/2013 21:18, Duncan Murdoch wrote:
On 13-04-23 3:51 PM, Patrick Burns wrote:
Okay, that's a good reason why it shouldn't. Why it should is that I want to substitute the first element of a call to be a function including the namespace.
Three ways: 1. Assign the function from the namespace locally, then call the local one. 2. Import the function in your NAMESPACE (if you know the name in advance). 3. Construct an expression involving ::, and substitute that in. For example: substitute(foo(x), list(foo=quote(baz::bar))) Duncan Murdoch
Pat On 23/04/2013 18:32, peter dalgaard wrote:
On Apr 23, 2013, at 19:23 , Patrick Burns wrote:
'as.name' doesn't recognize a name with its namespace extension as a name:
as.name("lm")
lm
as.name("stats::lm")
`stats::lm`
as.name("stats:::lm")
`stats:::lm` Is there a reason why it shouldn't?
Any reason why it should? :: and ::: are operators. foo$bar is not the same as `foo$bar` either.
-- Patrick Burns pburns at pburns.seanet.com twitter: @burnsstat @portfolioprobe http://www.portfolioprobe.com/blog http://www.burns-stat.com (home of: 'Impatient R' 'The R Inferno' 'Tao Te Programming')
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel