[R] substitute question

Gabor Grothendieck ggrothendieck at myway.com
Fri Mar 19 14:36:45 CET 2004


[This appears to have bounced so I am sending it again.  Apologies
if it gets there twice.]

Thanks. Thus it seems that there are two types of expressions and calls:

1. fully expanded 
2. partially expanded

and that fully expanded ones are a prerequisite for substitution.
body() and quote() produce such fully expanded expressions.

Using a small utility function we can investigate this:

recurse <- function( x, idx = NULL )
     if ( length( x ) > 0 ) { 
          for( i in seq( along = x ) )
               if (length(x[[i]])>1) 
                    Recall( x[[i]], c(idx, i))
               else {
                    if (length(idx)) cat(idx,"")
                    cat( i, class(x[[i]]), ":" )
                    cat( rep("\t",length(idx) + 2) )
                    print( x[[i]] )
               }
     }

f <- function(){a+1}

eb <- body(f)
class(eb)
recurse(eb)

eq <- quote(function(){a+1})
class(eq)
recurse(eq)

ep <- parse(text=deparse(f))
class(ep)
recurse(ep)


The output that the above is shown below. It shows that
body() and quote() produce fully expanded expression style objects
although body's is of class { and quote is of class call.

However, parse(text=deparse(f)) also produces a fully expanded
expression style object of class expression yet substitution 
does not occur with that. Thus full vs. partial expansion is likely
a necessary but not a sufficient condition. There is something
else but I don't know what it is.


> f <- function(){a+1}
> 
> eb <- body(f)
> class(eb)
[1] "{"
> recurse(eb)
1 name : `{`
2 1 name : `+`
2 2 name : a
2 3 numeric : [1] 1
> 
> eq <- quote(function(){a+1})
> class(eq)
[1] "call"
> recurse(eq) # lines begin with list indices and class name
1 name : `function`
2 NULL : NULL
3 1 name : `{`
3 2 1 name : `+`
3 2 2 name : a
3 2 3 numeric : [1] 1
4 NULL : NULL
> 
> ep <- parse(text=deparse(f))
> class(ep)
[1] "expression"
> recurse(ep)
1 1 name : `function`
1 2 NULL : NULL
1 3 1 name : `{`
1 3 2 1 name : `+`
1 3 2 2 name : a
1 3 2 3 numeric : [1] 1
1 4 NULL : NULL


Date: Thu, 18 Mar 2004 17:27:20 -0800 (PST) 
From: Thomas Lumley <tlumley at u.washington.edu>
To: Gabor Grothendieck <ggrothendieck at myway.com> 
Cc: <tplate at blackmesacapital.com>, <R-help at stat.math.ethz.ch> 
Subject: Re: [R] substitute question 


On Thu, 18 Mar 2004, Gabor Grothendieck wrote:

>
>
> I don't think I expressed myself very well on that.
>
> Looking at what we get from the example:
>
> > z <- substitute(substitute(expression(f),list(a=quote(b))),list(f=f))
>
> > z
> substitute(expression(function ()
> {
> a + 1
> }), list(a = quote(b)))
>
> > class(z);mode(z);typeof(z)
> [1] "call"
> [1] "call"
> [1] "language"
>
>
> we see that the function seems to be expanded correctly and
> the statement does produce a call object. However,
> applying eval one, two or three times does not give what
> you would think if you looked at z above.

Maybe we didn't express ourselves well enough.

Looking at z above isn't enough. z is a call to substitute().
Its first operand is an expression. The expression contains a single term,
which is a function.

If you typed
notz<- quote(substitute(expression(function ()
{
a + 1
}), list(a = quote(b))))

you would obtain something that deparsed the same as z, and so looked the
same, but was actually different. In notz the first operand of substitute
is an expression containing multiple terms, which if evaluated would
return a function.

substitute() goes though this expression and checks each term to see if it
is `a`. In z there is only one term and it isn't `a`. In notz there is
(after sufficient recursion) an `a` and it gets replaced.

So

> z[[2]][[2]]
function ()
{
a + 1
}
> notz[[2]][[2]]
function() {
a + 1
}

are the respective operands, and they still look the same. But

> mode(z[[2]][[2]])
[1] "function"
> mode(notz[[2]][[2]])
[1] "call"
> length(z[[2]][[2]])
[1] 1
> length(notz[[2]][[2]])
[1] 4

and if we try to find the actual `a` in there
> notz[[2]][[2]][[3]][[2]][[2]]
a
> z[[2]][[2]][[3]][[2]][[2]]
Error in z[[2]][[2]][[3]] : object is not subsettable
>


-thomas




More information about the R-help mailing list