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 _._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._