[R] substitute in a named expression

Peter Dalgaard p.dalgaard at biostat.ku.dk
Thu Jun 23 01:09:45 CEST 2005


Gabor Grothendieck <ggrothendieck at gmail.com> writes:

> On 6/22/05, Søren Højsgaard <Soren.Hojsgaard at agrsci.dk> wrote:
> > I have a 'named expression' like
> >  expr <- expression(rep(1,d))
> > and would like to replace the argument d with say 5 without actually evaluating the expression. So I try  substitute(expr, list(d=5)) in which case R simply returns expr which when I 'evaluate' it gives
> >  eval(expr)
> >  Error in rep.default(1, d) : invalid number of copies in rep()
> > 
> > I've looked at ?substitute and ?expression (and other places) for ideas, but - well I guess there are some details which I haven't quite understood. Can anyone point me in the right direction?
> 
> Try this:
> 
> eval(substitute(substitute(qq, list(d=5)), list(qq = expr[[1]])))
> 
> This aspect of R drove me crazy some time ago but Tony Plate finally figured 
> it out and discussed it some time back:
>    http://tolstoy.newcastle.edu.au/R/help/04/03/1247.html
> There is also a handy utility routine, esub, defined there.
> 
> The key points are:
> 
> - substitute won't go inside expressions but it will go inside call objects.
>   In this case your expr is an expression but expr[[1]] is a call object with
>   the desired contents.  Note that quote will return a call
>   object so you can avoid the [[1]] if you define expr as cl <- quote(rep(1,d))
>   i.e.  
>    cl <- quote(rep(1,d))
>    eval(substitute(substitute(cl, list(d=5)), list(cl = cl)))
> 
> - substitute autoquotes anything inside it so one must substitute in 
>   the first argument to the inner substitute using a second outer substitute.  
>   That is, the outer substitute substitutes expr[[1]] (which is evaluated) into 
>   the first argument of the inner substitute.
> 
> - the outer substitute wraps the result of the inner one in a call so we must 
>   perform an eval to get what is within the call.  This part is explained in
>   ?substitute
> 
> Sorry if this is complicated but that seems to be how it works.  Using
> the esub function defined in the link above you can simplify it substantially
> like this:
> 
> esub(cl, list(d=5))
> 
> # or
> 
> esub(expr[[1]], list(d=5))

Yes, substitute() is a bass-ackward design and the automatic quoting
of the first arg is a pain. It would have been much cleaner if
standard semantics were used and you'd just quote() the argument when
needed.

Your explanation of 

> eval(substitute(substitute(qq, list(d=5)), list(qq = expr[[1]])))
 
is a tad long-winded though.

What happens is that the inner unevaluated 

substitute(qq, list(d=5))

gets the qq replaced by the value of expr[[1]]. In casu it becomes

substitute(rep(1,d),list(d=5))

this then needs to be evaluated, yielding

rep(1,5)

-- 
   O__  ---- Peter Dalgaard             Øster Farimagsgade 5, Entr.B
  c/ /'_ --- Dept. of Biostatistics     PO Box 2099, 1014 Cph. K
 (*) \(*) -- University of Copenhagen   Denmark          Ph: (+45) 35327918
~~~~~~~~~~ - (p.dalgaard at biostat.ku.dk)                  FAX: (+45) 35327907




More information about the R-help mailing list