What's the Difference Between Substitute and Quote in R

What's the difference between substitute and quote in R

Here's an example that may help you to easily see the difference between quote() and substitute(), in one of the settings (processing function arguments) where substitute() is most commonly used:

f <- function(argX) {
list(quote(argX),
substitute(argX),
argX)
}

suppliedArgX <- 100
f(argX = suppliedArgX)
# [[1]]
# argX
#
# [[2]]
# suppliedArgX
#
# [[3]]
# [1] 100

How can one make visible the difference in the outputs of quote() and substitute()?

The reason is that the behavior of substitute() is different based on where you call it, or more precisely, what you are calling it on.

Understanding what will happen requires a very careful parsing of the (subtle) documentation for substitute(), specifically:

Substitution takes place by examining each component of the parse tree
as follows: If it is not a bound symbol in env, it is unchanged. If it
is a promise object, i.e., a formal argument to a function or
explicitly created using delayedAssign(), the expression slot of the
promise replaces the symbol. If it is an ordinary variable, its value
is substituted, unless env is .GlobalEnv in which case the symbol is
left unchanged.

So there are essentially three options.

In this case:

> df1 <- data.frame(a = 1, b = 2)
> identical(quote(df1),substitute(df1))
[1] TRUE

df1 is an "ordinary variable", but it is called in .GlobalEnv, since env argument defaults to the current evaluation environment. Hence we're in the very last case where the symbol, df1, is left unchanged and so it identical to the result of quote(df1).

In the context of the function:

is.identical <- function(X){
out <- identical(quote(X), substitute(X))
out
}

The important distinction is that now we're calling these functions on X, not df1. For most R users, this is a silly, trivial distinction, but when playing with subtle tools like substitute it becomes important. X is a formal argument of a function, so that implies we're in a different case of the documented behavior.

Specifically, it says that now "the expression slot of the promise replaces the symbol". We can see what this means if we debug() the function and examine the objects in the context of the function environment:

> debugonce(is.identical)
> is.identical(X = df1)
debugging in: is.identical(X = df1)
debug at #1: {
out <- identical(quote(X), substitute(X))
out
}
Browse[2]>
debug at #2: out <- identical(quote(X), substitute(X))
Browse[2]> str(quote(X))
symbol X
Browse[2]> str(substitute(X))
symbol df1
Browse[2]> Q

Now we can see that what happened is precisely what the documentation said would happen (Ha! So obvious! ;) )

X is a formal argument, or a promise, which according to R is not the same thing as df1. For most people writing functions, they are effectively the same, but the internal implementation disagrees. X is a promise object, and substitute replaces the symbol X with the one that it "points to", namely df1. This is what the docs mean by the "expression slot of the promise"; that's what R sees when in the X = df1 part of the function call.

To round things out, try to guess what will happen in this case:

is.identical <- function(X){
out <- identical(quote(A), substitute(A))
out
}

is.identical(X = df1)

(Hint: now A is not a "bound symbol in the environment".)

A final example illustrating more directly the final case in the docs with the confusing exception:

#Ordinary variable, but in .GlobalEnv
> a <- 2
> substitute(a)
a

#Ordinary variable, but NOT in .GlobalEnv
> e <- new.env()
> e$a <- 2
> substitute(a,env = e)
[1] 2

Why does substitute change noquote text to a string in R?

You're using the wrong function, use parse instead of noquote :

text<-'paste(italic(yes),"why not?")'
noquote_text <- parse(text=text)[[1]]

sub<- substitute(paste("Hi",noquote_text),env=list(noquote_text= noquote_text))
# paste("Hi", paste(italic(yes), "why not?"))

noquote just applies a class to an object of type character, with a specific print method not to show the quotes.

str(noquote("a"))
Class 'noquote' chr "a"
unclass(noquote("a"))
[1] "a"

Would you please elaborate on your answer?

In R you ought to be careful about the difference between what's in an object, and what is printed.

What noquote does is :

  • add "noquote" to the class attribute of the object
  • That's it

The code is :

function (obj) 
{
if (!inherits(obj, "noquote"))
class(obj) <- c(attr(obj, "class"), "noquote")
obj
}

Then when you print it, the methods print.noquote :

  • Removes the class "noquote" from the object if it's there
  • calls print with the argument quote = FALSE
  • that's it

You can actually call print.noquote on a string too :

print.noquote("a")
[1] a

It does print in a similar fashion as quote(a) or substitute(a) would but it's a totally different beast.

In the code you tried, you've been substituting a string instead of a call.

R substitute(), to substitute values in expression, is adding unnecessary quotes

Maybe I misunderstood what you are doing, but the following seems to work:

form  <- 'condition ~ (1|subject) + v'
var <- 'a'
covar <- c('b', 'c')

Then combine with paste and turn to formula directly:

covar <- paste(var, paste(covar, collapse=" + "), sep=" + ")
form <- formula(paste(form, covar, sep=" + "))

Output:

condition ~ (1 | subject) + v + a + b + c

Difference between quote and expression in R

  • expression returns its arguments as a vector of unevaluated expressions.
  • quote returns its argument as an unevaluated expression.

Try this:

(e1 <- quote(sin(x+y)))
# sin(x + y)
(e2 <- expression(sin(x+y)))
# expression(sin(x + y))
str(e1)
# language sin(x + y)
str(e2)
# expression(sin(x + y))
str(e2[[1]])
# language sin(x + y)
all.equal(e1, e2)
# [1] "Modes of target, current: call, expression" "target, current do not match when deparsed"
all.equal(e1, e2[[1]])
# [1] TRUE

Another example:

e2 = expression(sin(x+y), x+y)
e2
# expression(sin(x + y), x + y)
e2[1]
# expression(sin(x + y))
e2[2]
# expression(x + y)

R: Substitute variables bound in all parent environments

Building on @MikkoMarttila's answer, I think the following does what I requested

do_something <- function(todo) {

# A helper to substitute() in a pre-quoted expression
substitute_q <- function(expr, env) {
eval(substitute(substitute(x, env), list(x = expr)))
}

substitute_parents <- function(expr) {
expr <- substitute(expr)

# list all parent envs
envs <- list()
env <- environment()
while (!identical(env, globalenv())) {
envs <- c(envs, env)
env <- parent.env(env)
}
# substitute in all parent envs
for (e in envs) {
expr <- substitute_q(expr, e)
}

# previously did not include globalenv() and
# substitute() doesnt "substitute" there
e <- as.list(globalenv())
substitute_q(expr, e)
}

cat(
paste(
deparse(substitute_parents(todo)),
collapse = "\n"
)
)
}

This gives

nested_do <- function() {
var_2 <- "not_this"

do_something({
print(var_1)
Sys.sleep(100)
print("world")
print(var_2)
})
}

var_1 <- "hello"
var_2 <- "goodbye"

do_something({
print(var_1)
Sys.sleep(100)
print("world")
print(var_2)
})
#> {
#> print("hello")
#> Sys.sleep(100)
#> print("world")
#> print("goodbye")
#> }
nested_do()
#> {
#> print("hello")
#> Sys.sleep(100)
#> print("world")
#> print("goodbye")
#> }

Change the body of a function without quote marks

Assuming that the desired inputs are

  1. the modelstring function and
  2. the text of the replacement as a character string, userinput

use parse to convert the string to an expression and then add [[1]] on the end to convert that from an expression to a call object:

userinput <- "b.w[1]*X.w[i,1]^exp(b.w[2]*X.w[i,2])" # as in question
body(modelstring)[[2]][[4]][[2]][[3]] <- parse(text = userinput)[[1]]

modelstring
## function ()
## {
## for (h in (l1i1[j]):(l1i2[j])) {
## w[h] <- b.w[1] * X.w[i, 1]^exp(b.w[2] * X.w[i, 2])
## }
## }

Here is a simpler example that may be useful to play around with:

# inputs
f <- function() { 37 }
s <- "pi * pi"

body(f)[[2]] <- parse(text = s)[[1]]
f()
## [1] 9.869604


Related Topics



Leave a reply



Submit