Henrik Bengtsson
2002-Jan-23 17:50 UTC
[R] Question about substitute (and eval, parse and deparse)
I would like to define a function at run-time, but I just can't make it
work (please don't question why I want to do this, because that would be
too much to explain). For example, I want to define the the following
function
foo <- function(x) {
cat("Function", "foo", "was called with
argument", x, ".\n")
}
However, I would like to create similar function where 'foo' is replaced
with say 'bar' and 'x' is replaced with 'object'.
I'll use the variables
'name' and 'arg' for this purpose;
name <- "foo";
arg <- "x";
Now I'll create the 'call' to be evaluate to define the new
function:
call <- substitute(fcn <- function(arg) { cat("Function",
name, "was
called with argument", arg, ".\n"); },
list=list(fcn=as.name(name),
arg=as.name(arg), name=name))
Now looking at the call things look a little bit strange:
> print(call)
foo <- function(arg) {
cat("Function", "foo", "was called with
argument", x, ".\n")
}
> str(call)
language foo <- function(arg) { cat("Function",
"foo", "was called
with argument", x, ".\n") ...
Notice how the name ('foo') and the arguments to 'cat'
("foo", and 'x')
of the function are correct, but *not* the first argument/formal
('arg').
For me this is strange. Continuing anyway and evaluating this call by
> eval(call)
will define the function 'foo'. Now looking at this function we get
> print(foo)
function(arg) { cat("Function", name, "was called with
argument", arg,
".\n"); }
where we see that 'name' and 'arg' now is back!? If we instead
use
body() we get the following
> body(foo)
{
cat("Function", "foo", "was called with
argument", x, ".\n")
}
which is what we expected and finally
> attr(foo, "source")
[1] "function(arg) { cat(\"Function\", name, \"was called
with
argument\", arg, \".\\n\"); }"
which is not what we expected. Further more, calling 'foo' will *not*
work:
> foo(2)
Error in cat("Function", "foo", "was called with
argument", x, ".\n") :
Object "x" not found
> foo(x=2)
Error in foo(x = 2) : unused argument(s) (x ...)
> foo(arg=2)
Error in cat("Function", "foo", "was called with
argument", x, ".\n") :
Object "x" not found
I have also tried
call <- substitute(fcn <- function(arg) { cat("Function",
name,
"was called with argument", argName, ".\n"); },
list=list(fcn=as.name(name), arg=arg, name=name, argName=as.name(arg)))
with the same result. So, it comes to the argument/formal 'arg'.
A STEP CLOSER?
If one first deparse the call and the parse into a new call, which is then
evaluated by 'eval':
> eval(parse(text=deparse(call)))
then it the body of the function gets correct but I still have problem
with the arguments/formals:
> print(foo)
function(arg) {
cat("Function", "foo", "was called with
argument", x, ".\n")
}
> body(foo)
{
cat("Function", "foo", "was called with
argument", x, ".\n")
}
> attr(foo, "source")
[1] "function(arg) {"
[2] " cat(\"Function\", \"foo\", \"was called
with argument\", x,
\".\\n\")"
[3] "}"
So, what is going on here? How should I do this in a correct way?
I really appreciate your help!
Henrik Bengtsson
Dept. of Mathematical Statistics @ Centre for Mathematical Sciences
Lund Institute of Technology/Lund University, Sweden (+2h UTC)
Office: P316, +46 46 222 9611 (phone), +46 46 222 4623 (fax)
h b @ m a t h s . l t h . s e
http://www.maths.lth.se/matstat/staff/hb/
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
r-help mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !) To: r-help-request at
stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
Thomas Lumley
2002-Jan-23 18:28 UTC
[R] Question about substitute (and eval, parse and deparse)
On Wed, 23 Jan 2002, Henrik Bengtsson wrote:> I would like to define a function at run-time, but I just can't make it > work (please don't question why I want to do this, because that would be > too much to explain). For example, I want to define the the following > function > > foo <- function(x) { > cat("Function", "foo", "was called with argument", x, ".\n") > } > > However, I would like to create similar function where 'foo' is replaced > with say 'bar' and 'x' is replaced with 'object'. I'll use the variables > 'name' and 'arg' for this purpose; > > name <- "foo"; > arg <- "x"; > > Now I'll create the 'call' to be evaluate to define the new function: > > call <- substitute(fcn <- function(arg) { cat("Function", name, "was > called with argument", arg, ".\n"); }, list=list(fcn=as.name(name), > arg=as.name(arg), name=name))<and strange things happen> There are two issues here. One is that you really should have options(keep.source=FALSE) if you're going to do this sort of thing, for the sake of all our sanity. The other is that substitute() doesn't do formal arguments to functions. g<-eval(substitute( function(x){x+1}, list(x=as.name("y")) ))> gfunction (x) { y + 1 } I don't think this is precisely a bug, but it can be surprising. You need to set the formals() explicitly or use parse(deparse()). The `macros' example in the last R Newsletter involves creating functions at runtime a bit like this. You might find it helpful, but I think the easiest solution may be to find a way of not doing this. -thomas -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- r-help mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html Send "info", "help", or "[un]subscribe" (in the "body", not the subject !) To: r-help-request at stat.math.ethz.ch _._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._