Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

deparse(substitute()) returns function name normally, but function code when called inside for loop

I'm a bit surprised by R's behaviour in a very specific case. Let's say I define a function square that returns the square of its argument, like this:

square <- function(x) { return(x^2) }

I want to call this function within another function, and I also want to display its name when I do that. I can do that using deparse(substitute()). However, consider the following examples:

ds1 <- function(x) {
  print(deparse(substitute(x)))
}

ds1(square)
# [1] "square"

This is the expected output, so all is fine. However, if I pass the function wrapped in a list and process it using a for loop, the following happens:

ds2 <- function(x) {
  for (y in x) {
    print(deparse(substitute(y)))
  }
}

ds2(c(square))
# [1] "function (x) "   "{"               "    return(x^2)" "}"  

Can anybody explain to me why this occurs and how I could prevent it from happening?

like image 509
A. Stam Avatar asked Dec 20 '17 10:12

A. Stam


People also ask

What does Deparse substitute do in R?

substitute() is often paired with deparse() . That function takes the result of substitute() , an expression, and turns it into a character vector.

What does Deparse do in R?

deparse() function in R Language is used to convert an object of expression class to an object of character class.


1 Answers

As soon as you use x inside your function, it is evaluated, so it "stops being an (unevaluated) expression" and "starts being its resulting values (evaluated expression)". To prevent this, you must capture x by substitute before you use it for the first time.

The result of substitute is an object which you can query as if it was a list. So you can use

x <- substitute(x)

and then x[[1]] (the function name) and x[[2]] and following (the arguments of the function)

So this works:

ds2 <- function(x) {
    x <- substitute(x)
    # you can do `x[[1]]` but you can't use the expression object x in a
    # for loop. So you have to turn it into a list first
    for (y in as.list(x)[-1]) {
        print(deparse(y))
    }
}
ds2(c(square,sum))
## [1] "square"
## [1] "sum"
like image 163
akraf Avatar answered Sep 21 '22 15:09

akraf