Tony, Thomas, Thanks, again.
If the problem with my last example was just that I was passing a function rather than an unevaluated expression, then why don't the following return f with b in place of a? In both cases, a is still there in the final output. f <- function() { a + 1 } z <- substitute(substitute(f=f,list(a=quote(b))),list(f=parse(text=deparse(f)))) eval(eval(z)) or f <- function() { a + 1 } z <- substitute(substitute(expression(f),list(a=quote(b))),list(f=f)) eval(eval(eval(z))) --- Date: Thu, 18 Mar 2004 11:29:39 -0800 (PST) From: Thomas Lumley <[EMAIL PROTECTED]> To: Gabor Grothendieck <[EMAIL PROTECTED]> Cc: <[EMAIL PROTECTED]>, <[EMAIL PROTECTED]> Subject: RE: [R] substitute question On Thu, 18 Mar 2004, Gabor Grothendieck wrote: > > Tony, Thomas. Thanks for your help. Your comments were very > useful. > > Unfortunately, my next step gives me a new round of problems. > > The following is the same as the last example except that instead > of hard coding the function into the expression I wanted to > pass it to the expression. It seems like one has to do a double > substitute to get this effect but I am having problems getting this > to work. > The problem is that f is a function, not an expression. You need to work with body(f) Either > f<-function(){a+1}> body(f)<-do.call("substitute",list(body(f),list(a=quote(b))))> f function () { b + 1 } or > f<-function(){a+1} > body(f)<-eval(substitute(substitute(expr,list(a=quote(b))),list(expr=body(f)))) > f function () { b + 1 } -thomas --- Date: Thu, 18 Mar 2004 12:15:45 -0700 From: Tony Plate <[EMAIL PROTECTED]> To: <[EMAIL PROTECTED]> Cc: <[EMAIL PROTECTED]> Subject: RE: [R] substitute question Gabor, I suspect you are overlooking the fact that substitute() does not evaluate its first argument. So, in the previous example you were giving an unevaluated expression as the first argument of substitute(). In your most recent example you are supplying a function object as the first argument of substitute() (by supplying it as the value to be substituted for f). I think you can get what you want by first doing f <- Quote(function(){a+1}): > f <- Quote(function(){a+1}) > f function() { a + 1 } > z <- substitute(substitute(f,list(a=quote(b))),list(f=f)) > z substitute(function() { a + 1 }, list(a = quote(b))) > eval(z) function() { b + 1 } > eval(eval(z)) # this displays the "source" attribute function(){a+1} > body(eval(eval(z))) { b + 1 } > hope this helps, Tony Plate At Thursday 12:00 PM 3/18/2004, you wrote: >Tony, Thomas. Thanks for your help. Your comments were very >useful. > >Unfortunately, my next step gives me a new round of problems. > >The following is the same as the last example except that instead >of hard coding the function into the expression I wanted to >pass it to the expression. It seems like one has to do a double >substitute to get this effect but I am having problems getting this >to work. > >In the code below we first show that the keep.source option has been >set to FALSE so that the source attribute does not mislead us. > >Then we do a double substitute. The outer substitute just creates >the substitute that was in my previous question. This outer >substitute produces z, a call object. So far its as expected. > >We then do ze <- eval(z) but we get a function object right away. I was >expecting that we get an expression object. Even worse, the function does not >have a replaced with b -- even though this did work in the previous >example >that I posted. > >What's wrong? > > > > options()$keep.source >[1] FALSE > > f <- function(){a+1} > > z <- substitute(substitute(f,list(a=quote(b))),list(f=f)) > > class(z) >[1] "call" > > as.list(z) >[[1]] >substitute > >[[2]] >function () >{ > a + 1 >} > >[[3]] >list(a = quote(b)) > > > ze <- eval(z) > > class(ze) >[1] "function" > > ze >function () >{ > a + 1 >} > > attr(ze,"source") >NULL > > > >--- > >Date: Thu, 18 Mar 2004 09:00:02 -0800 (PST) >From: Thomas Lumley <[EMAIL PROTECTED]> >To: Gabor Grothendieck <[EMAIL PROTECTED]> >Cc: <[EMAIL PROTECTED]> >Subject: RE: [R] substitute question > > >On Wed, 17 Mar 2004, Gabor Grothendieck wrote: > > > > > > > I left out the brackets in my last email but the problem > > (a reappears after have been substituted out) still remains: > > > > > z <- substitute( function(){a+1}, list(a=quote(b)) ) > > > z > > function() { > > b + 1 > > } > > > eval(z) > > function(){a+1} > > >Interesting. > >Appearances are misleading, however: > > z <- substitute( function(){a+1}, list(a=quote(b)) ) > > z >function() { >b + 1 >} > > f<-eval(z) > > f() >Error in f() : Object "b" not found > > f >function(){a+1} > > attr(f,"source")<-NULL > > f >function () >{ >b + 1 >} > >So it isn't that eval(z) has a+1 inside, it just has a "source" attribute >with a+1. > >Looking more carefully at z > > as.list(z) >[[1]] >`function` > >[[2]] >NULL > >[[3]] >{ >b + 1 >} > >[[4]] >[1] "function(){a+1}" > >so the original construction of z has kept the source (not, however, as a >"source" attribute). > >There is method to our madness here. It is impossible (or at least too >complicated) to keep comments in the right place as a function is >parsed and deparsed. In the old days, comments would occasionally move >around, sometimes in very misleading ways (IIRC with if(){}else{} cases) > >Now we keep a copy of the source code with functions created interactively >or with source(), and drop the comments on parsing. This is controlled by >options("keep.source"). > >If you do a lot of substitute()-style programming you may want >options(keep.source=FALSE). > > -thomas > >PS: There are, of course, interesting possibilities for creative abuse of >the source attribute.... > >--- > >Date: Thu, 18 Mar 2004 08:41:54 -0700 >From: Tony Plate <[EMAIL PROTECTED]> >To: <[EMAIL PROTECTED]>, <[EMAIL PROTECTED]> >Subject: RE: [R] substitute question > > >This is because of the saved attribute "source" on z (that doesn't get >printed out before evaluating z, because z is not yet then a function). > >To complete your example: > > > z <- substitute( function(){a+1}, list(a=quote(b)) ) > > z >function() { >b + 1 >} > > eval(z) >function(){a+1} > > ze <- eval(z) > > attributes(ze) >$source >[1] "function(){a+1}" > > > attr(ze, "source") <- NULL > > ze >function () >{ >b + 1 >} > > > >I previously wrote on this topic: > >Date: Fri, 24 Oct 2003 09:42:55 -0600 >To: [EMAIL PROTECTED], Peter Dalgaard <[EMAIL PROTECTED]> >From: Tony Plate <[EMAIL PROTECTED]> >Subject: Re: [R] what's going on here with substitute() ? >Mime-Version: 1.0 >Content-Type: text/plain; charset="us-ascii"; format=flowed > >Peter, thank you for the explanation. This is indeed what is happening. > >Might I suggest the following passage for inclusion in the help page for >"function", and possibly also "body", in the DETAILS or WARNING section: > >"Note that the text of the original function definition is saved as an >attribute "source" on the function, and this is printed out when the >function is printed. Hence, if the function body is changed in some way >other than by assigning a value via body() (which removes the "source" >attribute), the printed form of the function may not be the same as the >actual function body." > >Something along these lines could also go in the help for "eval", though if >it were only there it might be very difficult to find if one were trying to >look up puzzling behavior of a function. > >Here is a transcript that shows what is happening, with another suggestion >following it. > > > eval(substitute(this.is.R <- function() X, >list(X=!is.null(options("CRAN")[[1]])))) > > this.is.R >function() X > > body(this.is.R) >[1] TRUE > > attributes(this.is.R) >$source >[1] "function() X" > > attributes(this.is.R) <- NULL > > this.is.R >function () >TRUE > > # the "source" attribute comes from function definition: > > attributes(function() X) >$source >[1] "function() X" > > # and seems to be added by "eval": > > attr(eval(parse(text="function() TRUE")[[1]]), "source") >[1] "function() TRUE" > > > > > # we can assign bogus "source" > > attr(this.is.R, "source") <- "a totally bogus function body" > > this.is.R >a totally bogus function body > > # assigning to body() removes "source" > > body(this.is.R) <- list(666) > > this.is.R >function () >666 > > attr(this.is.R, "source") >NULL > > > >An even better approach might be something that gave a warning on printing >if the parsed "source" attribute was not identical to the language object >being printed. This would probably belong in the code for "case LANGSXP:" >in the function PrintValueRec in main/print.c (if it were written in R, I >could contribute a patch, but right now I don't have time to try to >understand the C there.) R code to do the test could be something like this: > > > f <- this.is.R > > identical(f, eval(parse(text=attr(f, "source"))[[1]])) >[1] FALSE > > f <- function() TRUE > > identical(f, eval(parse(text=attr(f, "source"))[[1]])) >[1] TRUE > > > >-- Tony Plate > > >At Wednesday 08:09 PM 3/17/2004, Gabor Grothendieck wrote: > > > >I left out the brackets in my last email but the problem > >(a reappears after have been substituted out) still remains: > > > > > z <- substitute( function(){a+1}, list(a=quote(b)) ) > > > z > >function() { > > b + 1 > >} > > > eval(z) > >function(){a+1} > > > > > > > >--- > >Date: Wed, 17 Mar 2004 20:10:43 -0500 (EST) > >From: Gabor Grothendieck <[EMAIL PROTECTED]> > >[ Add to Address Book | Block Address | Report as Spam ] > >To: <[EMAIL PROTECTED]> > >Subject: [R] substitute question > > > > > > > > > > > > > >Consider the following example: > > > ># substitute a with b in the indicated function. Seems to work. > > > z <- substitute( function()a+1, list(a=quote(b)) ) > > > z > >function() b + 1 > > > ># z is an object of class call so use eval > ># to turn it into an object of class expression; however, > ># when z is evaluated, the variable a returns. > > > eval(z) > >function()a+1 > > > >Why did a suddenly reappear again after it had already been replaced? > ______________________________________________ [EMAIL PROTECTED] mailing list https://www.stat.math.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide! http://www.R-project.org/posting-guide.html