0

I want to pass arguments to a function that aren't to be evaluated until they're used within the function. As a trivial example, how would I go about if I wanted to pass ... = foo, 'bar' to the following function, while foo is defined within the function:

  myfunc <- function(X, ...) {    
    for (foo in seq_along(X)) {
      cat(..., '\n')
    }
  }
  myfunc(X = 1:5, foo, 'bar')

I tried using cat(substitute(...), '\n'), which seems to merely omit foo.

Thanks!

MrFlick
  • 195,160
  • 17
  • 277
  • 295
Comfort Eagle
  • 2,112
  • 2
  • 22
  • 44
  • Yes, I initially would like all parameters to be evaluated in the function environment. How would you go about and name the parameters with special rules? – Comfort Eagle Aug 04 '20 at 22:55

2 Answers2

2

1) Use eval(substitute(...))

myfunc <- function(X, ...) {    
  for (foo in seq_along(X)) {
    eval(substitute(cat(..., "\n")))
  }
}
myfunc(X = 1:5, foo, 'bar')

giving:

1 bar 
2 bar 
3 bar 
4 bar 
5 bar 

2) defmacro Another approach is to create a macro using defmacro in gtools:

library(gtools)

myfunc2 <- defmacro(X, DOTS, expr = {
  for (foo in seq_along(X)) {
    cat(..., "\n")
  }
})
myfunc2(X = 1:5, foo, 'bar')
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
1

Here's one way

myfunc <- function(X, ...) { 
  dots <- eval(substitute(alist(...)))
  for (foo in seq_along(X)) {
    do.call("cat", c(dots, '\n'))
  }
}
myfunc(X = 1:5, foo, 'bar')
# 1 bar 
# 2 bar 
# 3 bar 
# 4 bar 
# 5 bar 

we capture all the parameters passed to the ... in an unevaluated pair list. We then use "do.call" to inject those values into a call to cat() and evaluate in the local environment.

This would work as long as you don't need to do something like

test <- function() {
  bar <- "bar"
  myfunc(X = 1:5, foo, bar)
}
test()
#  Error in cat(foo, bar, "\n") : object 'bar' not found 
MrFlick
  • 195,160
  • 17
  • 277
  • 295