10

In a simple function using ... to supply a list of arguments, is it possible for that function to find the names of the objects passed from the calling environment? If so, how?

This arises in the context of the question, printing matrices and vectors side by side, but is probably more general.

In that context, the arguments ... can also include character strings, for which no names are required. Here is my MWE, where I tried using deparse(substitute()), but to no avail.

test_names <- function(...) {
  # get arguments
  args <- list(...)
  chars <- sapply(args, is.character)
  names <- sapply(args, function(x) if(is.character(x)) " " else deparse(substitute(x)))
  names
}

Test:

A = matrix(c(0.5, 1, 3, 0.75, 2.8, 4), nrow = 2)
x = c(0.5, 3.7, 2.3)
y = c(0.7, -1.2)
b = A %*% x - y

> test_names(A, " * ", x, " - ", y, " = ", b)
[1] "X[[i]]" " "      "X[[i]]" " "      "X[[i]]" " "      "X[[i]]"
> 

My desired output for this would be the character vector of length 7:

[1] "A"  " "   "x" " "  "y" " "   "b"

It is surprising here that the results are all X[[i]], when there is no X mentioned anywhere.

Following @Roland's answer, this seems to do what I want:

test_names2 <- function(...) {
  argnames <- sys.call()
  unlist(lapply(argnames[-1], as.character))
}

> test_names2(A, " * ", x, " - ", y, " = ", b)
[1] "A"   " * " "x"   " - " "y"   " = " "b"  
Community
  • 1
  • 1
user101089
  • 3,756
  • 1
  • 26
  • 53

2 Answers2

13

Use sys.call:

test_names <- function(...) {
  argnames <- sys.call()
  paste(lapply(argnames[-1], as.character), collapse = "")
}
#[1] "A * x - y = b"
Roland
  • 127,288
  • 10
  • 191
  • 288
7

As the email list describes (here) either sys.call as Roland said or match.call can be used for this.

In comparison to Roland's solution, a solution with match.call looks like

f = function(...){
  return(match.call())
}

d = f(x = 1, b = 5)
d
#f(x = 1, b = 5)
as.list(d[-1])
#$x
#[1] 1
#
#$b
#[1] 5

So use it somewhat like this, because the first element is the name of the function itself.

f = function(...){
  return(as.list(match.call())[-1])
}

They are similar, but the help page says:

sys.call() is similar [to match.call()], but does not expand the argument names;

So here's one difference.

catastrophic-failure
  • 3,759
  • 1
  • 24
  • 43