11

I need a function that accepts an arbitrary number of arguments and stores them in a variable as an expression without evaluating them. I managed to do it with match.call but it seems a little "kludgy".

foo <- function(...) {
  expr <- match.call()
  expr[[1]] <- expression
  expr <- eval(expr)
  # do some stuff with expr
  return(expr)
}

> bla
Error: object 'bla' not found
> foo(x=bla, y=2)
expression(x = bla, y = 2)

Clarification

To clarify, I'm asking how to write a function that behaves like expression(). I can't use expression() directly for reasons that are too long to explain.

Ernest A
  • 7,526
  • 8
  • 34
  • 40
  • Look at these two questions http://stackoverflow.com/questions/12416880/getting-names-from-dots and http://stackoverflow.com/questions/3057341/how-to-use-rs-ellipsis-feature-when-writing-your-own-function Also look at the results for a search on [r] ellipsis – mnel Nov 13 '12 at 00:24
  • 1
    Right now it seems `foo <- expression` would just do it, no? What do you mean by "`# do some stuff with expr`"? – flodel Nov 13 '12 at 00:29
  • Just posted my answer and realised your comment is a far simpler approach – mnel Nov 13 '12 at 00:34
  • @flodel nice one... it's a bit complicated to explain here ... in reality `foo` returns another function that uses the variable `expr` defined in `foo`. to put it another way `expr` is a free variable in the anonymous function returned by `foo`. so, it's not just like `expression` :) – Ernest A Nov 13 '12 at 00:41
  • 1
    Have a look at the function `.` in `plyr` it may do what you want or at least point you in the right direction – mnel Nov 13 '12 at 00:44
  • @mnel the `.` function does `as.list(match.call()[-1])` which returns an unevaluated list, then an expression can be created with `as.expression`. thanks. – Ernest A Nov 13 '12 at 00:48
  • 1
    It's unlikely that you actually need an expression object - a list of calls is usually adequate. – hadley Nov 13 '12 at 04:15

3 Answers3

25

The most idiomatic way is:

f <- function(x, y, ...) {
  match.call(expand.dots = FALSE)$`...`
}
hadley
  • 102,019
  • 32
  • 183
  • 245
  • 2
    +1 Idiomatic indeed - and it is used widely in base R, e.g. in the code for linear models specified via a formula in `lm()`. – Gavin Simpson Nov 13 '12 at 08:20
5

Using . from plyr as a prototype

foo <-   function (...) 
  {
  as.expression(as.list(match.call()[-1]))
  }
mnel
  • 113,303
  • 27
  • 265
  • 254
3

The ultimate intended outcome is slightly vague (could you clarify a bit?). However, this may be helpful:

foo2 <- function(...) {
  expr <- as.list(substitute(list(...)))[-1L]
  class(expr) <- "expression"
  expr
}

example:

foo2(x=bla, y=2)
# expression(x = bla, y = 2)
Ricardo Saporta
  • 54,400
  • 17
  • 144
  • 178
  • glad to help. If it suits, please feel free to give it the tick mark – Ricardo Saporta Nov 13 '12 at 01:03
  • i give you the tick although i'm probably going to use @mnel's solution because is a little bit cleaner – Ernest A Nov 13 '12 at 01:29
  • @ErnestA Well then you should have put the tick on the other answer! :) It's still unclear how specifically you are using this. If you will use `match.call()` take a look at the documentation for `expand.dots`, as you might need to set that to `FALSE`. – Ricardo Saporta Nov 13 '12 at 03:12